[BROWSEUI]
authorDavid Quintana <gigaherz@gmail.com>
Mon, 8 Sep 2014 01:59:18 +0000 (01:59 +0000)
committerDavid Quintana <gigaherz@gmail.com>
Mon, 8 Sep 2014 01:59:18 +0000 (01:59 +0000)
* Initial implementation of the explorer command line parser. Not used by explorer-new, yet.

svn path=/branches/shell-experiments/; revision=64081

dll/win32/browseui/CMakeLists.txt
dll/win32/browseui/browseuiord.cpp
dll/win32/browseui/parsecmdline.cpp [new file with mode: 0644]
include/psdk/shlwapi.h
include/psdk/shlwapi_undoc.h

index 73272ff..fe0dbe2 100644 (file)
@@ -24,6 +24,7 @@ list(APPEND SOURCE
     commonbrowser.cpp
     globalfoldersettings.cpp
     internettoolbar.cpp
+    parsecmdline.cpp
     regtreeoptions.cpp
     shellbrowser.cpp
     toolsband.cpp
index 4ad2d87..6f4d869 100644 (file)
@@ -58,10 +58,7 @@ extern "C" long WINAPI SHCreateFromDesktop(long param8)
 /*************************************************************************
  * SHExplorerParseCmdLine              [BROWSEUI.107]
  */
-extern "C" long WINAPI SHExplorerParseCmdLine(LPCTSTR commandLine)
-{
-    return -1;
-}
+/****** MOVED TO parsecmdline.cpp ******/
 
 /*************************************************************************
  * UEMRegisterNotify                   [BROWSEUI.118]
diff --git a/dll/win32/browseui/parsecmdline.cpp b/dll/win32/browseui/parsecmdline.cpp
new file mode 100644 (file)
index 0000000..d2a0d2f
--- /dev/null
@@ -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;
+}
index 835029a..ed9ee36 100644 (file)
@@ -1862,6 +1862,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
 #define SHACF_FILESYSTEM            0x00000001
index 46d4d08..00f3ca2 100644 (file)
@@ -45,6 +45,45 @@ struct IEThreadParamBlock
        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 @@ void WINAPI InitOCHostClass(long param8);
 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);