Index: base/shell/explorer-new/explorer.c =================================================================== --- base/shell/explorer-new/explorer.c (revision 51441) +++ base/shell/explorer-new/explorer.c (working copy) @@ -20,21 +20,289 @@ #include +HRESULT WINAPI SHOpenFolderAndSelectItems( + IN PCIDLIST_ABSOLUTE pidlFolder, + UINT cidl, + IN OPTIONAL PCUITEMID_CHILD_ARRAY *apidl, + DWORD dwFlags +); + HINSTANCE hExplorerInstance; HMODULE hUser32; HANDLE hProcessHeap; HKEY hkExplorer = NULL; DRAWCAPTEMP DrawCapTemp = NULL; +/* undoc GUID */ +DEFINE_GUID(CLSID_RebarBandSite, 0xECD4FC4D, 0x521C, 0x11D0, 0xB7, 0x92, 0x00, 0xA0, 0xC9, 0x03, 0x12, 0xE1); + typedef struct _LANGCODEPAGE { WORD wLanguage; WORD wCodePage; } LANGCODEPAGE, *PLANGCODEPAGE; -/* undoc GUID */ -DEFINE_GUID(CLSID_RebarBandSite, 0xECD4FC4D, 0x521C, 0x11D0, 0xB7, 0x92, 0x00, 0xA0, 0xC9, 0x03, 0x12, 0xE1); +/* return values */ +#define NOT_ENOUGH_MEMORY 1 +#define IO_ERROR 2 +/* common check of memory allocation results */ +#define CHECK_ENOUGH_MEMORY(p) \ +if (!(p)) \ +{ \ + fprintf(stderr,"%s: file %s, line %d: Not enough memory\n", \ + getAppName(), __FILE__, __LINE__); \ + exit(NOT_ENOUGH_MEMORY); \ +} + +//FIXME: move to resource files. We could add /help or /? to show user usage +static const char *usage = + "Syntax:\n" + "EXPLORER.EXE [/n][/e][,/root,][[,/select],]\n" + "Usage:\n" + "/n: Opens a new window in single-paned (My Computer) view for each item\n" + "selected, even if the new window duplicates a window that is\n" + "already open.\n" + "/e: Uses ReactOS Explorer view. ReactOS Explorer view is most similar\n" + "to File Manager in Windows version 3.x. Note that the default view\n" + "is Open view.\n" + "/root,: Specifies the root level of the specified view. The\n" + "default is to use the normal namespace root (the desktop).\n" + "Whatever is specified is the root for the display.\n" + "/select,: Specifies the folder to receive the initial\n" + "focus. If '/select' is used, the parent folder\n" + "is opened and the specified object is selected.\n"; + +typedef enum +{ + ACTION_SELECT, ACTION_ROOT, ACTION_EXPLVIEW, ACTION_NEWWINDOW +} EXPLORER_ACTION; + +const CHAR *getAppName(void) +{ + return "explorer"; +} + +/****************************************************************************** + * Allocates memory and converts input from wide chars to multibyte + * Returned string must be freed by the caller + */ +char* GetMultiByteString(const WCHAR* strW) +{ + if(strW) + { + char* strA; + int len = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL); + + strA = HeapAlloc(GetProcessHeap(), 0, len); + CHECK_ENOUGH_MEMORY(strA); + WideCharToMultiByte(CP_ACP, 0, strW, -1, strA, len, NULL, NULL); + return strA; + } + return NULL; +} + +/****************************************************************************** + * Copies file name from command line string to the buffer. + * Rewinds the command line string pointer to the next non-space character + * after the file name. + * Buffer contains an empty string if no filename was found; + * + * params: + * command_line - command line current position pointer + * where *s[0] is the first symbol of the file name. + * file_name - buffer to write the file name to. + */ +void get_file_name(LPWSTR *command_line, LPWSTR file_name) +{ + WCHAR *s = *command_line; + int pos = 0; /* position of pointer "s" in *command_line */ + file_name[0] = 0; + + if (!s[0]) + { + return; + } + + if (s[0] == L'"') + { + s++; + (*command_line)++; + while(s[0] != L'"') + { + if (!s[0]) + { + fprintf(stderr, "%s: Unexpected end of file name!\n", getAppName()); + exit(1); + } + s++; + pos++; + } + } + else + { + while(s[0] && !iswspace(s[0])) + { + s++; + pos++; + } + } + memcpy(file_name, *command_line, pos * sizeof((*command_line)[0])); + /* remove the last backslash */ + if (file_name[pos - 1] == L'\\') + { + file_name[pos - 1] = L'\0'; + } + else + { + file_name[pos] = L'\0'; + } + + if (s[0]) + { + s++; + pos++; + } + while(s[0] && iswspace(s[0])) + { + s++; + pos++; + } + (*command_line) += pos; +} + + +BOOL PerformExplAction(EXPLORER_ACTION action, LPWSTR s) +{ + wchar_t fpath[MAX_PATH]; + get_file_name(&s, fpath); + + switch (action) + { + case ACTION_SELECT: + { + if (!fpath[0]) + { + fprintf(stderr, "%s: No file name is specified\n", getAppName()); + fprintf(stderr, usage); + exit(4); + } + else + { + PIDLIST_ABSOLUTE pidlFolder; + + pidlFolder = ILCreateFromPath(fpath); + if (pidlFolder) + { + /* SHOpenFolderAndSelectItems is unimplemented in shlfolder.c + Problems? Take look at + http://www.eggheadcafe.com/software/aspnet/32763916/problem-trapping-shopenfolderandselectitems.aspx*/ + SHOpenFolderAndSelectItems(pidlFolder, 0, NULL, 0); + ILFree(pidlFolder); + } + } + break; + } + case ACTION_EXPLVIEW: + //FIXME /e + break; + + case ACTION_NEWWINDOW: + { + //FIXME: Open folder '/n,' + } + break; + + case ACTION_ROOT: + //FIXME /root, + break; + + default: + action = ACTION_NEWWINDOW; + break; + } + return TRUE; +} + +BOOL ProcessCmdLine(LPWSTR lpCmdLine) +{ + EXPLORER_ACTION action = ACTION_NEWWINDOW;; + LPWSTR s = lpCmdLine; /* command line pointer */ + WCHAR ch = *s; /* current character */ + + while (ch && (ch == L'/')) + { + WCHAR chu; + WCHAR ch2; + + s++; + ch = *s; + ch2 = *(s + 1); + chu = (WCHAR)towupper(ch); + if (!ch2 || iswspace(ch2)) + { + { + switch (chu) + { + case L'E': + { + action = ACTION_EXPLVIEW; + } + break; + + default: + action = ACTION_NEWWINDOW; + break; + } + } + s++; + } + else + { + if (ch2 == L',') + { + switch (chu) + { + case L'N': //option '/n,' + + s += 2; + action = ACTION_NEWWINDOW; + break; + default: + action = ACTION_NEWWINDOW; + break; + } + } + else + { + if (!_wcsnicmp(s, L"SELECT,", 7)) //there we deal with multi-letter options + { + s += 7; + action = ACTION_SELECT; + } + else + // this is a file name, starting from '/' + s--; + break; + } + } + + /* skip spaces to the next parameter */ + ch = *s; + while (ch && iswspace(ch)) + { + s++; + ch = *s; + } + } + + //if (action == ACTION_UNDEF) + // return FALSE; + + return PerformExplAction(action, s); +} + + LONG SetWindowStyle(IN HWND hWnd, IN LONG dwStyleMask, @@ -350,6 +618,19 @@ return bRet; } +static void HideMinimizedWindows(BOOL hide) +{ + MINIMIZEDMETRICS mm; + mm.cbSize = sizeof(MINIMIZEDMETRICS); + SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &mm, FALSE); + if(hide) + mm.iArrange |= ARW_HIDE; + else + mm.iArrange &= ~ARW_HIDE; + SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &mm, FALSE); +} + + INT WINAPI _tWinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, @@ -393,7 +674,9 @@ if (RegisterTrayWindowClass() && RegisterTaskSwitchWndClass()) { Tray = CreateTrayWindow(); - + + HideMinimizedWindows(TRUE); + if (Tray != NULL) hShellDesktop = DesktopCreateWindow(Tray); } @@ -404,10 +687,11 @@ } else { - /* A shell is already loaded. Parse the command line arguments - and unless we need to do something specific simply display - the desktop in a separate explorer window */ - /* FIXME */ + /* A shell is already loaded. Parse the command line arguments */ + if (ProcessCmdLine(lpCmdLine)) + { + return 0; + } } if (Tray != NULL)