From 499bb6d2d79cc8baf1c5d453ee19fc4b17eb1102 Mon Sep 17 00:00:00 2001 From: Martin Fuchs Date: Wed, 5 Oct 2005 23:05:13 +0000 Subject: [PATCH] implemented command line parser for Explorer svn path=/trunk/; revision=18284 --- reactos/subsys/system/explorer/doc/TODO.txt | 1 - reactos/subsys/system/explorer/explorer.cpp | 135 +++++++++++++++--- reactos/subsys/system/explorer/explorer.h | 36 +++++ .../system/explorer/shell/filechild.cpp | 2 + .../system/explorer/shell/mainframe.cpp | 44 +++--- .../subsys/system/explorer/shell/mainframe.h | 11 +- .../system/explorer/shell/shellbrowser.cpp | 18 +-- 7 files changed, 190 insertions(+), 57 deletions(-) diff --git a/reactos/subsys/system/explorer/doc/TODO.txt b/reactos/subsys/system/explorer/doc/TODO.txt index 3eaaa08b057..ef35cabb975 100644 --- a/reactos/subsys/system/explorer/doc/TODO.txt +++ b/reactos/subsys/system/explorer/doc/TODO.txt @@ -7,7 +7,6 @@ - implement Drag Drop from the tree view. - activate accelerator keys like in shell view folders - program manager "progman" DDE server -- command line parameters like "/e,/root,c:\" and "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\::{21EC2020-3AEA-1069-A2DD-08002B30309D}" (launch of control panel) - Windows-key combos - Application Desktop Toolbars - hide CVS subdirectories, may be even implement a CVS managment plugin diff --git a/reactos/subsys/system/explorer/explorer.cpp b/reactos/subsys/system/explorer/explorer.cpp index 22b83b6133f..c11ac81ab2f 100644 --- a/reactos/subsys/system/explorer/explorer.cpp +++ b/reactos/subsys/system/explorer/explorer.cpp @@ -533,8 +533,10 @@ ResBitmap::ResBitmap(UINT nid) #ifndef ROSSHELL -void explorer_show_frame(int cmdshow, LPTSTR lpCmdLine) +void explorer_show_frame(int cmdShow, LPTSTR lpCmdLine) { + ExplorerCmd cmd; + if (g_Globals._hMainWnd) { if (IsIconic(g_Globals._hMainWnd)) ShowWindow(g_Globals._hMainWnd, SW_RESTORE); @@ -553,21 +555,121 @@ void explorer_show_frame(int cmdshow, LPTSTR lpCmdLine) if (mdiStr.empty()) Dialog::DoModal(IDD_MDI_SDI, WINDOW_CREATOR(MdiSdiDlg), g_Globals._hwndDesktop); - // Now read the setting again and interpret it as boolean value. - bool mdi = XMLBool(explorer_options, "mdi", true); + // Now read the MDI attribute again and interpret it as boolean value. + cmd._mdi = XMLBool(explorer_options, "mdi", true); + + cmd._cmdShow = cmdShow; + + // parse command line options, which may overwrite the MDI flag + cmd.ParseCmdLine(lpCmdLine); // create main window - MainFrameBase::Create(lpCmdLine, mdi, cmdshow); + MainFrameBase::Create(cmd); +} + +bool ExplorerCmd::ParseCmdLine(LPCTSTR lpCmdLine) +{ + bool ok = true; + + LPCTSTR b = lpCmdLine; + LPCTSTR p = b; + + while(*b) { + // remove leading space + while(_istspace((unsigned)*b)) + ++b; + + p = b; + + bool quote = false; + + // options are separated by ',' + for(; *p; ++p) { + if (*p == '"') // Quote characters may appear at any position in the command line. + quote = !quote; + else if (*p==',' && !quote) + break; + } + + if (p > b) { + int l = p - b; + + // remove trailing space + while(l>0 && _istspace((unsigned)b[l-1])) + --l; + + if (!EvaluateOption(String(b, l))) + ok = false; + + if (*p) + ++p; + + b = p; + } + } + + return ok; +} + +bool ExplorerCmd::EvaluateOption(LPCTSTR option) +{ + String opt_str; + + // Remove quote characters, as they are evaluated at this point. + for(; *option; ++option) + if (*option != '"') + opt_str += *option; + + option = opt_str; + + if (option[0] == '/') { + ++option; + + // option /e for windows in explorer mode + if (!_tcsicmp(option, TEXT("e"))) + _flags |= OWM_EXPLORE; + // option /root for rooted explorer windows + else if (!_tcsicmp(option, TEXT("root"))) + _flags |= OWM_ROOTED; + // non-standard options: /mdi, /sdi + else if (!_tcsicmp(option, TEXT("mdi"))) + _mdi = true; + else if (!_tcsicmp(option, TEXT("sdi"))) + _mdi = false; + else + return false; + } else { + if (!_path.empty()) + return false; + + _path = opt_str; + } + + return true; +} + +bool ExplorerCmd::IsValidPath() const +{ + if (!_path.empty()) { + DWORD attribs = GetFileAttributes(_path); + + if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY)) + return true; // file system path + else if (*_path==':' && _path.at(1)==':') + return true; // text encoded IDL + } + + return false; } #else -void explorer_show_frame(int cmdshow, LPTSTR lpCmdLine) +void explorer_show_frame(int cmdShow, LPTSTR lpCmdLine) { if (!lpCmdLine) lpCmdLine = TEXT("explorer.exe"); - launch_file(GetDesktopWindow(), lpCmdLine, cmdshow); + launch_file(GetDesktopWindow(), lpCmdLine, cmdShow); } #endif @@ -671,7 +773,7 @@ static void InitInstance(HINSTANCE hInstance) } -int explorer_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdshow) +int explorer_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdShow) { CONTEXT("explorer_main"); @@ -686,14 +788,14 @@ int explorer_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdshow) } #ifndef ROSSHELL - if (cmdshow != SW_HIDE) { + if (cmdShow != SW_HIDE) { /* // don't maximize if being called from the ROS desktop - if (cmdshow == SW_SHOWNORMAL) + if (cmdShow == SW_SHOWNORMAL) ///@todo read window placement from registry - cmdshow = SW_MAXIMIZE; + cmdShow = SW_MAXIMIZE; */ - explorer_show_frame(cmdshow, lpCmdLine); + explorer_show_frame(cmdShow, lpCmdLine); } #endif @@ -721,10 +823,10 @@ int main(int argc, char* argv[]) LPWSTR cmdline = GetCommandLineW(); - while(*cmdline && !_istspace(*cmdline)) + while(*cmdline && !_istspace((unsigned)*cmdline)) ++cmdline; - while(_istspace(*cmdline)) + while(_istspace((unsigned)*cmdline)) ++cmdline; return wWinMain(GetModuleHandle(NULL), 0, cmdline, nShowCmd); @@ -929,17 +1031,12 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL #ifndef ROSSHELL if (g_Globals._hwndDesktop) g_Globals._desktop_mode = true; - - /**TODO fix command line handling */ - if (*lpCmdLine=='"' && lpCmdLine[_tcslen(lpCmdLine)-1]=='"') { - ++lpCmdLine; - lpCmdLine[_tcslen(lpCmdLine)-1] = '\0'; - } #endif int ret = explorer_main(hInstance, lpCmdLine, nShowCmd); + // write configuration file g_Globals.write_persistent(); diff --git a/reactos/subsys/system/explorer/explorer.h b/reactos/subsys/system/explorer/explorer.h index 4704e654a0f..3ad9a52e454 100644 --- a/reactos/subsys/system/explorer/explorer.h +++ b/reactos/subsys/system/explorer/explorer.h @@ -72,6 +72,42 @@ #include "shell/filechild.h" #include "shell/shellbrowser.h" + #ifndef ROSSHELL + + /// Explorer command line parser + // for commands like "/e,/root,c:\" + // or "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\::{21EC2020-3AEA-1069-A2DD-08002B30309D}" (launch of control panel) +struct ExplorerCmd +{ + ExplorerCmd() + : _flags(0), + _cmdShow(SW_SHOWNORMAL), + _mdi(false), + _valid_path(false) + { + } + + ExplorerCmd(LPCTSTR url, bool mdi) + : _path(url), + _flags(0), + _cmdShow(SW_SHOWNORMAL), + _mdi(mdi), + _valid_path(true) //@@ + { + } + + bool ParseCmdLine(LPCTSTR lpCmdLine); + bool EvaluateOption(LPCTSTR option); + bool IsValidPath() const; + + String _path; + int _flags; // OPEN_WINDOW_MODE + int _cmdShow; + bool _mdi; + bool _valid_path; +}; + #include "shell/mainframe.h" + #endif diff --git a/reactos/subsys/system/explorer/shell/filechild.cpp b/reactos/subsys/system/explorer/shell/filechild.cpp index aecca310544..fe27b011b1a 100644 --- a/reactos/subsys/system/explorer/shell/filechild.cpp +++ b/reactos/subsys/system/explorer/shell/filechild.cpp @@ -228,6 +228,8 @@ FileChildWindow::FileChildWindow(HWND hwnd, const FileChildWndInfo& info) _root._entry->_data.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; + ///@todo use OWM_ROOTED flag + if (info._open_mode & OWM_EXPLORE) ///@todo Is not-explore-mode for FileChildWindow completely implemented? _left_hwnd = *(_left=new Pane(_hwnd, IDW_TREE_LEFT, IDW_HEADER_LEFT, _root._entry, true, COL_CONTENT)); diff --git a/reactos/subsys/system/explorer/shell/mainframe.cpp b/reactos/subsys/system/explorer/shell/mainframe.cpp index 096dd2b2160..a9fd2cfadd6 100644 --- a/reactos/subsys/system/explorer/shell/mainframe.cpp +++ b/reactos/subsys/system/explorer/shell/mainframe.cpp @@ -38,12 +38,12 @@ extern HWND create_webchildwindow(const WebChildWndInfo& info); #include "../dialogs/settings.h" // for MdiSdiDlg -HWND MainFrameBase::Create(LPCTSTR path, bool mdi, UINT cmdshow) +HWND MainFrameBase::Create(const ExplorerCmd& cmd) { HWND hFrame; -#ifndef _NO_MDI ///@todo implement command line option to switch between MDI and SDI - if (mdi) +#ifndef _NO_MDI + if (cmd._mdi) hFrame = MDIMainFrame::Create(); else #endif @@ -54,32 +54,20 @@ HWND MainFrameBase::Create(LPCTSTR path, bool mdi, UINT cmdshow) g_Globals._hMainWnd = hFrame; - if (path) { - static String sPath = path; // copy path to avoid accessing freed memory - path = sPath; - } - if (hwndOld) DestroyWindow(hwndOld); - ShowWindow(hFrame, cmdshow); + ShowWindow(hFrame, cmd._cmdShow); UpdateWindow(hFrame); - bool valid_dir = false; - - if (path) { - DWORD attribs = GetFileAttributes(path); - - if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY)) - valid_dir = true; - else if (*path==':' || *path=='"') - valid_dir = true; - } - // Open the first child window after initializing the application - if (valid_dir) - PostMessage(hFrame, PM_OPEN_WINDOW, 0, (LPARAM)path); - else + if (cmd.IsValidPath()) { + // We use the static s_path variable to store the path string in order + // to avoid accessing prematurely freed memory in the PostMessage handlers. + static String s_path = cmd._path; + + PostMessage(hFrame, PM_OPEN_WINDOW, cmd._flags, (LPARAM)(LPCTSTR)s_path); + } else PostMessage(hFrame, PM_OPEN_WINDOW, OWM_EXPLORE|OWM_DETAILS, 0); } @@ -989,7 +977,7 @@ LRESULT MDIMainFrame::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) create_info._pos.rcNormalPosition.right = CW_USEDEFAULT; create_info._pos.rcNormalPosition.bottom = CW_USEDEFAULT; - create_info._open_mode = (OPEN_WINDOW_MODE)wparam; + create_info._open_mode = wparam; // FileChildWindow::create(_hmdiclient, create_info); return (LRESULT)MDIShellBrowserChild::create(create_info); @@ -1149,7 +1137,7 @@ int MDIMainFrame::Command(int id, int code) break; case ID_VIEW_SDI: - MainFrameBase::Create(NULL, false); + MainFrameBase::Create(ExplorerCmd()); break; case IDW_COMMANDBAR: @@ -1516,7 +1504,7 @@ LRESULT SDIMainFrame::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) root_path = path; } - jump_to(root_path, (OPEN_WINDOW_MODE)wparam); //@todo content of 'path' not used any more + jump_to(root_path, wparam); //@todo content of 'path' not used any more return TRUE;} // success default: def: @@ -1530,7 +1518,7 @@ int SDIMainFrame::Command(int id, int code) { switch(id) { case ID_VIEW_MDI: - MainFrameBase::Create(_url, true); + MainFrameBase::Create(ExplorerCmd(_url, true)); break; case IDW_COMMANDBAR: @@ -1632,6 +1620,8 @@ void SDIMainFrame::update_shell_browser() delete _shellBrowser.release(); } + ///@todo use OWM_ROOTED flag + // create explorer treeview if (_shellpath_info._open_mode & OWM_EXPLORE) { if (!_left_hwnd) { diff --git a/reactos/subsys/system/explorer/shell/mainframe.h b/reactos/subsys/system/explorer/shell/mainframe.h index 900a890e8f5..a3e36a7275a 100644 --- a/reactos/subsys/system/explorer/shell/mainframe.h +++ b/reactos/subsys/system/explorer/shell/mainframe.h @@ -27,7 +27,14 @@ #define PM_OPEN_WINDOW (WM_APP+0x07) -enum OPEN_WINDOW_MODE {OWM_EXPLORE=1, OWM_DETAILS=2, OWM_PIDL=4, OWM_SEPARATE=8}; + +enum OPEN_WINDOW_MODE { + OWM_EXPLORE=1, /// window in explore mode + OWM_ROOTED=2, /// "rooted" window with special shell namespace root + OWM_DETAILS=4, /// view files in detail mode + OWM_PIDL=8, /// path is given as PIDL, otherwise as LPCTSTR + OWM_SEPARATE=16 /// open separate subfolder windows +}; /// Explorer frame window base class @@ -38,7 +45,7 @@ struct MainFrameBase : public PreTranslateWindow MainFrameBase(HWND hwnd); ~MainFrameBase(); - static HWND Create(LPCTSTR path, bool mdi=true, UINT cmdshow=SW_SHOWNORMAL); + static HWND Create(const ExplorerCmd& cmd); static int OpenShellFolders(LPIDA pida, HWND hFrameWnd); WindowHandle _hwndrebar; diff --git a/reactos/subsys/system/explorer/shell/shellbrowser.cpp b/reactos/subsys/system/explorer/shell/shellbrowser.cpp index c2d296d158f..cd63816fa0e 100644 --- a/reactos/subsys/system/explorer/shell/shellbrowser.cpp +++ b/reactos/subsys/system/explorer/shell/shellbrowser.cpp @@ -112,17 +112,17 @@ void ShellBrowser::jump_to(LPCITEMIDLIST pidl) if (!_cur_dir) _cur_dir = static_cast(_root._entry); -/*@todo - we should call read_tree() here to iterate through the hierarchy and open all folders from shell_info._root_shell_path to shell_info._shell_path - _root._entry->read_tree(shell_info._root_shell_path.get_folder(), info._shell_path, SORT_NAME); - -> see FileChildWindow::FileChildWindow() -*/ - - LOG(FmtString(TEXT("ShellBrowser::jump_to(): pidl=%s"), (LPCTSTR)FileSysShellPath(pidl))); + //LOG(FmtString(TEXT("ShellBrowser::jump_to(): pidl=%s"), (LPCTSTR)FileSysShellPath(pidl))); if (_cur_dir) { static DynamicFct ILFindChild(TEXT("SHELL32"), 24); +/*@todo + we should call read_tree() here to iterate through the hierarchy and open all folders from _create_info._root_shell_path (_cur_dir) to _create_info._shell_path (pidl) + _root._entry->read_tree(_create_info._root_shell_path.get_folder(), info._shell_path, SORT_NAME); + -> see FileChildWindow::FileChildWindow()_create_info._shell_path +*/ + LPCITEMIDLIST child_pidl; if (ILFindChild) @@ -582,7 +582,7 @@ LRESULT MDIShellBrowserChild::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) break; case ID_VIEW_SDI: - MainFrameBase::Create(_url, false); + MainFrameBase::Create(ExplorerCmd(_url, false)); break; default: @@ -606,6 +606,8 @@ void MDIShellBrowserChild::update_shell_browser() delete _shellBrowser.release(); } + ///@todo use OWM_ROOTED flag + // create explorer treeview if (_create_info._open_mode & OWM_EXPLORE) { if (!_left_hwnd) {