Author: dquintana Date: Mon Sep 8 01:59:18 2014 New Revision: 64081
URL: http://svn.reactos.org/svn/reactos?rev=64081&view=rev Log: [BROWSEUI] * Initial implementation of the explorer command line parser. Not used by explorer-new, yet.
Added: branches/shell-experiments/dll/win32/browseui/parsecmdline.cpp (with props) Modified: branches/shell-experiments/dll/win32/browseui/CMakeLists.txt branches/shell-experiments/dll/win32/browseui/browseuiord.cpp branches/shell-experiments/include/psdk/shlwapi.h branches/shell-experiments/include/psdk/shlwapi_undoc.h
Modified: branches/shell-experiments/dll/win32/browseui/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/dll/win32/brow... ============================================================================== --- branches/shell-experiments/dll/win32/browseui/CMakeLists.txt [iso-8859-1] (original) +++ branches/shell-experiments/dll/win32/browseui/CMakeLists.txt [iso-8859-1] Mon Sep 8 01:59:18 2014 @@ -24,6 +24,7 @@ commonbrowser.cpp globalfoldersettings.cpp internettoolbar.cpp + parsecmdline.cpp regtreeoptions.cpp shellbrowser.cpp toolsband.cpp
Modified: branches/shell-experiments/dll/win32/browseui/browseuiord.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/dll/win32/brow... ============================================================================== --- branches/shell-experiments/dll/win32/browseui/browseuiord.cpp [iso-8859-1] (original) +++ branches/shell-experiments/dll/win32/browseui/browseuiord.cpp [iso-8859-1] Mon Sep 8 01:59:18 2014 @@ -58,10 +58,7 @@ /************************************************************************* * SHExplorerParseCmdLine [BROWSEUI.107] */ -extern "C" long WINAPI SHExplorerParseCmdLine(LPCTSTR commandLine) -{ - return -1; -} +/****** MOVED TO parsecmdline.cpp ******/
/************************************************************************* * UEMRegisterNotify [BROWSEUI.118]
Added: branches/shell-experiments/dll/win32/browseui/parsecmdline.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/dll/win32/brow... ============================================================================== --- branches/shell-experiments/dll/win32/browseui/parsecmdline.cpp (added) +++ branches/shell-experiments/dll/win32/browseui/parsecmdline.cpp [iso-8859-1] Mon Sep 8 01:59:18 2014 @@ -0,0 +1,417 @@ +/* +* ReactOS browseui +* +* Copyright 2014 David Quintana gigaherz@gmail.com +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "precomp.h" +#include <strsafe.h> + +extern "C" +BOOL WINAPI GUIDFromStringW( + _In_ PCWSTR psz, + _Out_ LPGUID pguid + ); + +static BOOL _CopyAndUnquoteText(LPCWSTR strFieldSource, LPWSTR strField, size_t cchField) +{ + WCHAR cChar; + PWSTR tmpField = strField; + size_t lenField = 1; + BOOL inQuote = FALSE; + + // Remove leading whitespace + cChar = *strFieldSource; + while (cChar == L' ' || cChar == L'\t' || cChar == L'\n' || cChar == L'\r') + { + strFieldSource = CharNextW(strFieldSource); + cChar = *strFieldSource; + } + + while (cChar && cChar != L'=' && cChar != L',') + { + if (cChar == L'"') + { + // [1] is always valid read because of null-termination + if (inQuote && strFieldSource[1] == L'"') + { + if (lenField < cchField) + { + // Append + *(tmpField++) = L'"'; + ++lenField; + } + + // Skip second quote + strFieldSource++; + } + else + { + inQuote = !inQuote; + } + } + else + { + if (inQuote || (cChar != L'=' && cChar != L',')) + { + if (lenField < cchField) + { + // Append + *(tmpField++) = cChar; + ++lenField; + } + } + } + + strFieldSource = CharNextW(strFieldSource); + cChar = *strFieldSource; + } + + // Remove trailing whitespace + while (tmpField > strField) + { + tmpField = CharPrevW(strField, tmpField); + cChar = *tmpField; + if (cChar != L' ' && cChar != L'\t' && cChar != L'\n' && cChar != L'\r') + { + tmpField = CharNextW(tmpField); + break; + } + } + + // Terminate output string + *tmpField = 0; + + return TRUE; +} + +static BOOL _FindNextArg(PCWSTR * pstrFieldSource) +{ + PCWSTR strFieldSource = *pstrFieldSource; + WCHAR cChar = *strFieldSource; + BOOL inQuote = FALSE; + + while (cChar) + { + if (!inQuote && (cChar == L'=' || cChar == L',')) + break; + + if (cChar == L'"') + inQuote = !inQuote; + + strFieldSource = CharNextW(strFieldSource); + cChar = *strFieldSource; + } + + if (cChar == 0) + { + *pstrFieldSource = strFieldSource; + return FALSE; + } + + *pstrFieldSource = CharNextW(strFieldSource); + return TRUE; +} + +static PCWSTR _FindFirstField(PCWSTR strFieldSource) +{ + //Find end of first arg, because + // behaviour is different if the first separator is an '=' + BOOL inQuote = FALSE; + PCWSTR tmpArgs = strFieldSource; + WCHAR cChar = *tmpArgs; + while (cChar) + { + if (cChar == L'=') + break; + + if (cChar == L',') + break; + + if (cChar == L'"') + inQuote = !inQuote; + + tmpArgs = CharNextW(tmpArgs); + cChar = *tmpArgs; + } + + // Skip the text before the first equal sign, if not quoted, unless the arg 0 was requested. + if (*tmpArgs == L'=' && !inQuote) + { + strFieldSource = ++tmpArgs; + TRACE("Skipped content before the first '=', remainder=%S\n", strFieldSource); + } + + return strFieldSource; +} + +static BOOL _ReadNextArg(PCWSTR * pstrFieldSource, PWSTR strField, size_t cchField) +{ + // Copy and unquote text + _CopyAndUnquoteText(*pstrFieldSource, strField, cchField); + + return _FindNextArg(pstrFieldSource); +} + +static LPITEMIDLIST _ILReadFromSharedMemory(PCWSTR strField) +{ + LPITEMIDLIST ret = NULL; + + // Ensure it really is an IDLIST-formatted parameter + // Format for IDLIST params: ":pid:shared" + if (*strField != L':') + return NULL; + + HANDLE hData = (HANDLE) StrToIntW(strField + 1); + PWSTR strSecond = StrChrW(strField + 1, L':'); + + if (strSecond) + { + int pid = StrToIntW(strSecond + 1); + void* pvShared = SHLockShared(hData, pid); + if (pvShared) + { + ret = ILClone((LPCITEMIDLIST) pvShared); + SHUnlockShared(pvShared); + SHFreeShared(hData, pid); + } + } + return ret; +} + +static HRESULT _ParsePathToPidl(PWSTR strPath, LPITEMIDLIST * pidl) +{ + CComPtr<IShellFolder> psfDesktop; + + HRESULT hr = SHGetDesktopFolder(&psfDesktop); + if (FAILED(hr)) + return hr; + + return psfDesktop->ParseDisplayName(NULL, NULL, strPath, NULL, pidl, NULL); +} + +static LPITEMIDLIST _GetDocumentsPidl() +{ + CComPtr<IShellFolder> ppshf; + LPITEMIDLIST pidl; + WCHAR guid [] = L"::{450d8fba-ad25-11d0-98a8-0800361b1103}"; + + if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_MYDOCUMENTS, &pidl))) + return pidl; + + if (FAILED(SHGetDesktopFolder(&ppshf))) + return NULL; + + if (FAILED(ppshf->ParseDisplayName(NULL, NULL, guid, NULL, &pidl, NULL))) + return NULL; + + return pidl; +} + +/************************************************************************* +* SHExplorerParseCmdLine [BROWSEUI.107] +*/ +extern "C" +UINT +WINAPI +SHExplorerParseCmdLine(ExplorerCommandLineParseResults * pInfo) +{ + WCHAR strField[MAX_PATH]; + WCHAR strDir[MAX_PATH]; + + PCWSTR strCmdLine = GetCommandLineW(); + PCWSTR strFieldArray = PathGetArgsW(strCmdLine); + + if (!*strFieldArray) + { + pInfo->dwFlags = 9; + pInfo->pidlPath = _GetDocumentsPidl(); + if (!pInfo->pidlPath) + { + GetWindowsDirectoryW(strDir, MAX_PATH); + PathStripToRootW(strDir); + pInfo->pidlPath = ILCreateFromPathW(strDir); + } + return (LONG) (pInfo->pidlPath); + } + + PCWSTR strNextArg = _FindFirstField(strFieldArray); + + BOOL hasNext = TRUE; + + hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField)); + while (TRUE) + { + // Basic flags-only params first + if (!StrCmpIW(strField, L"/N")) + { + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_N | SH_EXPLORER_CMDLINE_FLAG_ONE; + TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags); + } + else if (!StrCmpIW(strField, L"/S")) + { + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_S; + TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags); + } + else if (!StrCmpIW(strField, L"/E")) + { + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_E; + TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags); + } + else if (!StrCmpIW(strField, L"/SELECT")) + { + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_SELECT; + TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags); + } + else if (!StrCmpIW(strField, L"/NOUI")) + { + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_NOUI; + TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags); + } + else if (!StrCmpIW(strField, L"-embedding")) + { + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_EMBED; + TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags); + } + else if (!StrCmpIW(strField, L"/SEPARATE")) + { + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_SEPARATE; + TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags); + } + else if (!StrCmpIW(strField, L"/INPROC")) + { + // No idea what Inproc is supposed to do, but it gets a GUID, and parses it. + + TRACE("CmdLine Parser: Found %S flag\n", strField); + + if (!hasNext) + return FALSE; + + hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField)); + + if (!GUIDFromStringW(strField, &(pInfo->guidInproc))) + return FALSE; + + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_INPROC; + + TRACE("CmdLine Parser: Parsed /INPROC flag. dwFlags=%08lx, guidInproc=%S\n", pInfo->dwFlags, strField); + } + else if (!StrCmpIW(strField, L"/ROOT")) + { + LPITEMIDLIST pidlRoot = NULL; + + // The window should be rooted + + TRACE("CmdLine Parser: Found %S flag\n", strField); + + if (!pInfo->pidlPath) + return FALSE; + + if (!hasNext) + return FALSE; + + hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField)); + + // Root may be a pidl + if (!StrCmpIW(strField, L"/IDLIST")) + { + if (hasNext) + { + hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField)); + } + pidlRoot = _ILReadFromSharedMemory(strField); + } + else + { + // Or just a path string + _ParsePathToPidl(strField, &pidlRoot); + } + + pInfo->pidlRoot = pidlRoot; + + // The root defaults to the desktop + if (!pidlRoot) + { + if (FAILED(SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &(pInfo->pidlRoot)))) + pInfo->pidlRoot = NULL; + } + + // TODO: Create rooted PIDL from pInfo->pidlPath and pInfo->pidlRoot + + TRACE("CmdLine Parser: Parsed /ROOT flag. dwFlags=%08lx, pidlRoot=%p\n", pInfo->dwFlags, pInfo->pidlRoot); + } + else + { + // Anything else is part of the target path to browse to + TRACE("CmdLine Parser: Found target path %S\n", strField); + + // Which can be a shared-memory itemidlist + if (!StrCmpIW(strField, L"/IDLIST")) + { + LPITEMIDLIST pidlArg; + + if (!hasNext) + return FALSE; + + hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField)); + pidlArg = _ILReadFromSharedMemory(strField); + if (!pidlArg) + return FALSE; + + if (pInfo->pidlPath) + ILFree(pInfo->pidlPath); + pInfo->pidlPath = pidlArg; + + TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, pidlPath=%p\n", pInfo->dwFlags, pInfo->pidlPath); + } + else + { + // Or just a plain old string. + + LPITEMIDLIST pidlPath = ILCreateFromPathW(strField); + + pInfo->pidlPath = pidlPath; + + if (pidlPath) + { + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_IDLIST; + TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, pidlPath=%p\n", pInfo->dwFlags, pInfo->pidlPath); + } + else + { + // The path could not be parsed into an ID List, + // so pass it on as a plain string. + + PWSTR field = StrDupW(strField); + pInfo->strPath = field; + if (field) + { + pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_STRING; + TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, strPath=%S\n", pInfo->dwFlags, field); + } + } + + } + } + + if (!hasNext) + break; + hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField)); + } + + return TRUE; +}
Propchange: branches/shell-experiments/dll/win32/browseui/parsecmdline.cpp ------------------------------------------------------------------------------ svn:eol-style = native
Modified: branches/shell-experiments/include/psdk/shlwapi.h URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/include/psdk/s... ============================================================================== --- branches/shell-experiments/include/psdk/shlwapi.h [iso-8859-1] (original) +++ branches/shell-experiments/include/psdk/shlwapi.h [iso-8859-1] Mon Sep 8 01:59:18 2014 @@ -1861,6 +1861,30 @@ HRESULT WINAPI SHCreateStreamWrapper(LPBYTE,DWORD,DWORD,struct IStream**);
#endif /* NO_SHLWAPI_STREAM */ + +#ifndef NO_SHLWAPI_SHARED + +PVOID +WINAPI +SHLockShared( + _In_ HANDLE hData, + _In_ DWORD dwProcessId + ); + +BOOL +WINAPI +SHUnlockShared( + _In_ void *pvData + ); + +BOOL +WINAPI +SHFreeShared( + _In_ HANDLE hData, + _In_ DWORD dwProcessId + ); + +#endif /* NO_SHLWAPI_SHARED */
/* SHAutoComplete flags */ #define SHACF_DEFAULT 0x00000000
Modified: branches/shell-experiments/include/psdk/shlwapi_undoc.h URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/include/psdk/s... ============================================================================== --- branches/shell-experiments/include/psdk/shlwapi_undoc.h [iso-8859-1] (original) +++ branches/shell-experiments/include/psdk/shlwapi_undoc.h [iso-8859-1] Mon Sep 8 01:59:18 2014 @@ -45,6 +45,45 @@ long filler4; // unknown contents };
+struct ExplorerCommandLineParseResults +{ + LPWSTR strPath; + LPITEMIDLIST pidlPath; + DWORD dwFlags; + DWORD unk_12; + DWORD unk_16; + DWORD unk_20; + DWORD unk_24; + DWORD unk_28; + LPITEMIDLIST pidlRoot; + DWORD unk_36; + DWORD unk_40; + DWORD unk_44; + DWORD unk_48; + GUID guidInproc; +}; + +#define SH_EXPLORER_CMDLINE_FLAG_ONE 0x00000001 +#define SH_EXPLORER_CMDLINE_FLAG_S 0x00000002 +// unknown/unused 0x00000004 +#define SH_EXPLORER_CMDLINE_FLAG_E 0x00000008 +// unknown/unused 0x00000010 +// unknown/unused 0x00000020 +#define SH_EXPLORER_CMDLINE_FLAG_SELECT 0x00000040 +#define SH_EXPLORER_CMDLINE_FLAG_EMBED 0x00000080 +// unknown/unused 0x00000100 +#define SH_EXPLORER_CMDLINE_FLAG_IDLIST 0x00000200 +#define SH_EXPLORER_CMDLINE_FLAG_INPROC 0x00000400 +// unknown/unused 0x00000800 +#define SH_EXPLORER_CMDLINE_FLAG_NOUI 0x00001000 +// unknown/unused 0x00002000 +#define SH_EXPLORER_CMDLINE_FLAG_N 0x00004000 +// unknown/unused 0x00008000 +// unknown/unused 0x00010000 +#define SH_EXPLORER_CMDLINE_FLAG_SEPARATE 0x00020000 +#define SH_EXPLORER_CMDLINE_FLAG_STRING 0x02000000 + + BOOL WINAPI SHAboutInfoA(LPSTR lpszDest, DWORD dwDestLen); BOOL WINAPI SHAboutInfoW(LPWSTR lpszDest, DWORD dwDestLen); HRESULT WINAPI IUnknown_QueryStatus(IUnknown *lpUnknown, REFGUID pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT* pCmdText); @@ -86,7 +125,7 @@ long WINAPI SHOpenFolderWindow(IEThreadParamBlock *param8); void WINAPI SHCreateSavedWindows(void); long WINAPI SHCreateFromDesktop(long param8); -long WINAPI SHExplorerParseCmdLine(LPCTSTR commandLine); +UINT WINAPI SHExplorerParseCmdLine(ExplorerCommandLineParseResults * pParseResults); void WINAPI UEMRegisterNotify(long param8, long paramC); HRESULT WINAPI SHCreateBandForPidl(LPCITEMIDLIST param8, IUnknown *paramC, BOOL param10); HRESULT WINAPI SHPidlFromDataObject(IDataObject *param8, long *paramC, long param10, FILEDESCRIPTORW *param14);