ReactOS  0.4.13-dev-249-gcba1a2f
parsecmdline.cpp
Go to the documentation of this file.
1 /*
2 * ReactOS browseui
3 *
4 * Copyright 2014 David Quintana <gigaherz@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 
21 #include "precomp.h"
22 #include <strsafe.h>
23 
24 extern "C"
26  _In_ PCWSTR psz,
27  _Out_ LPGUID pguid
28  );
29 
30 static BOOL _CopyAndUnquoteText(LPCWSTR strFieldSource, LPWSTR strField, size_t cchField)
31 {
32  WCHAR cChar;
33  PWSTR tmpField = strField;
34  size_t lenField = 1;
35  BOOL inQuote = FALSE;
36 
37  // Remove leading whitespace
38  cChar = *strFieldSource;
39  while (cChar == L' ' || cChar == L'\t' || cChar == L'\n' || cChar == L'\r')
40  {
41  strFieldSource = CharNextW(strFieldSource);
42  cChar = *strFieldSource;
43  }
44 
45  while (cChar && cChar != L'=' && cChar != L',')
46  {
47  if (cChar == L'"')
48  {
49  // [1] is always valid read because of null-termination
50  if (inQuote && strFieldSource[1] == L'"')
51  {
52  if (lenField < cchField)
53  {
54  // Append
55  *(tmpField++) = L'"';
56  ++lenField;
57  }
58 
59  // Skip second quote
60  strFieldSource++;
61  }
62  else
63  {
64  inQuote = !inQuote;
65  }
66  }
67  else
68  {
69  if (inQuote || (cChar != L'=' && cChar != L','))
70  {
71  if (lenField < cchField)
72  {
73  // Append
74  *(tmpField++) = cChar;
75  ++lenField;
76  }
77  }
78  }
79 
80  strFieldSource = CharNextW(strFieldSource);
81  cChar = *strFieldSource;
82  }
83 
84  // Remove trailing whitespace
85  while (tmpField > strField)
86  {
87  tmpField = CharPrevW(strField, tmpField);
88  cChar = *tmpField;
89  if (cChar != L' ' && cChar != L'\t' && cChar != L'\n' && cChar != L'\r')
90  {
91  tmpField = CharNextW(tmpField);
92  break;
93  }
94  }
95 
96  // Terminate output string
97  *tmpField = 0;
98 
99  return TRUE;
100 }
101 
102 static BOOL _FindNextArg(PCWSTR * pstrFieldSource)
103 {
104  PCWSTR strFieldSource = *pstrFieldSource;
105  WCHAR cChar = *strFieldSource;
106  BOOL inQuote = FALSE;
107 
108  while (cChar)
109  {
110  if (!inQuote && (cChar == L'=' || cChar == L','))
111  break;
112 
113  if (cChar == L'"')
114  inQuote = !inQuote;
115 
116  strFieldSource = CharNextW(strFieldSource);
117  cChar = *strFieldSource;
118  }
119 
120  if (cChar == 0)
121  {
122  *pstrFieldSource = strFieldSource;
123  return FALSE;
124  }
125 
126  *pstrFieldSource = CharNextW(strFieldSource);
127  return TRUE;
128 }
129 
130 static PCWSTR _FindFirstField(PCWSTR strFieldSource)
131 {
132  //Find end of first arg, because
133  // behaviour is different if the first separator is an '='
134  BOOL inQuote = FALSE;
135  PCWSTR tmpArgs = strFieldSource;
136  WCHAR cChar = *tmpArgs;
137  while (cChar)
138  {
139  if (cChar == L'=')
140  break;
141 
142  if (cChar == L',')
143  break;
144 
145  if (cChar == L'\"')
146  inQuote = !inQuote;
147 
148  tmpArgs = CharNextW(tmpArgs);
149  cChar = *tmpArgs;
150  }
151 
152  // Skip the text before the first equal sign, if not quoted, unless the arg 0 was requested.
153  if (*tmpArgs == L'=' && !inQuote)
154  {
155  strFieldSource = ++tmpArgs;
156  TRACE("Skipped content before the first '=', remainder=%S\n", strFieldSource);
157  }
158 
159  return strFieldSource;
160 }
161 
162 static BOOL _ReadNextArg(PCWSTR * pstrFieldSource, PWSTR strField, size_t cchField)
163 {
164  // Copy and unquote text
165  _CopyAndUnquoteText(*pstrFieldSource, strField, cchField);
166 
167  return _FindNextArg(pstrFieldSource);
168 }
169 
171 {
173 
174  // Ensure it really is an IDLIST-formatted parameter
175  // Format for IDLIST params: ":pid:shared"
176  if (*strField != L':')
177  return NULL;
178 
179  HANDLE hData = IntToPtr(StrToIntW(strField + 1));
180  PWSTR strSecond = StrChrW(strField + 1, L':');
181 
182  if (strSecond)
183  {
184  int pid = StrToIntW(strSecond + 1);
185  void* pvShared = SHLockShared(hData, pid);
186  if (pvShared)
187  {
188  ret = ILClone((LPCITEMIDLIST) pvShared);
189  SHUnlockShared(pvShared);
190  SHFreeShared(hData, pid);
191  }
192  }
193  return ret;
194 }
195 
197 {
198  CComPtr<IShellFolder> psfDesktop;
199 
200  HRESULT hr = SHGetDesktopFolder(&psfDesktop);
201  if (FAILED(hr))
202  return hr;
203 
204  return psfDesktop->ParseDisplayName(NULL, NULL, strPath, NULL, pidl, NULL);
205 }
206 
208 {
209  CComPtr<IShellFolder> ppshf;
210  LPITEMIDLIST pidl;
211  WCHAR guid [] = L"::{450d8fba-ad25-11d0-98a8-0800361b1103}";
212 
214  return pidl;
215 
216  if (FAILED(SHGetDesktopFolder(&ppshf)))
217  return NULL;
218 
219  if (FAILED(ppshf->ParseDisplayName(NULL, NULL, guid, NULL, &pidl, NULL)))
220  return NULL;
221 
222  return pidl;
223 }
224 
225 /*************************************************************************
226 * SHExplorerParseCmdLine [BROWSEUI.107]
227 */
228 extern "C"
229 UINT_PTR
230 WINAPI
232 {
233  WCHAR strField[MAX_PATH];
234  WCHAR strDir[MAX_PATH];
235 
236  PCWSTR strCmdLine = GetCommandLineW();
237  PCWSTR strFieldArray = PathGetArgsW(strCmdLine);
238 
239  if (!*strFieldArray)
240  {
241  pInfo->dwFlags = 9;
242  pInfo->pidlPath = _GetDocumentsPidl();
243  if (!pInfo->pidlPath)
244  {
246  PathStripToRootW(strDir);
247  pInfo->pidlPath = ILCreateFromPathW(strDir);
248  }
249  return (LONG_PTR)(pInfo->pidlPath);
250  }
251 
252  PCWSTR strNextArg = _FindFirstField(strFieldArray);
253 
254  BOOL hasNext = TRUE;
255 
256  hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
257  while (TRUE)
258  {
259  // Basic flags-only params first
260  if (!StrCmpIW(strField, L"/N"))
261  {
263  TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
264  }
265  else if (!StrCmpIW(strField, L"/S"))
266  {
268  TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
269  }
270  else if (!StrCmpIW(strField, L"/E"))
271  {
273  TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
274  }
275  else if (!StrCmpIW(strField, L"/SELECT"))
276  {
278  TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
279  }
280  else if (!StrCmpIW(strField, L"/NOUI"))
281  {
283  TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
284  }
285  else if (!StrCmpIW(strField, L"-embedding"))
286  {
288  TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
289  }
290  else if (!StrCmpIW(strField, L"/SEPARATE"))
291  {
293  TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
294  }
295  else if (!StrCmpIW(strField, L"/INPROC"))
296  {
297  // No idea what Inproc is supposed to do, but it gets a GUID, and parses it.
298 
299  TRACE("CmdLine Parser: Found %S flag\n", strField);
300 
301  if (!hasNext)
302  return FALSE;
303 
304  hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
305 
306  if (!GUIDFromStringW(strField, &(pInfo->guidInproc)))
307  return FALSE;
308 
310 
311  TRACE("CmdLine Parser: Parsed /INPROC flag. dwFlags=%08lx, guidInproc=%S\n", pInfo->dwFlags, strField);
312  }
313  else if (!StrCmpIW(strField, L"/ROOT"))
314  {
315  LPITEMIDLIST pidlRoot = NULL;
316 
317  // The window should be rooted
318 
319  TRACE("CmdLine Parser: Found %S flag\n", strField);
320 
321  if (!pInfo->pidlPath)
322  return FALSE;
323 
324  if (!hasNext)
325  return FALSE;
326 
327  hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
328 
329  // Root may be a pidl
330  if (!StrCmpIW(strField, L"/IDLIST"))
331  {
332  if (hasNext)
333  {
334  hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
335  }
336  pidlRoot = _ILReadFromSharedMemory(strField);
337  }
338  else
339  {
340  // Or just a path string
341  _ParsePathToPidl(strField, &pidlRoot);
342  }
343 
344  pInfo->pidlRoot = pidlRoot;
345 
346  // The root defaults to the desktop
347  if (!pidlRoot)
348  {
350  pInfo->pidlRoot = NULL;
351  }
352 
353  // TODO: Create rooted PIDL from pInfo->pidlPath and pInfo->pidlRoot
354 
355  TRACE("CmdLine Parser: Parsed /ROOT flag. dwFlags=%08lx, pidlRoot=%p\n", pInfo->dwFlags, pInfo->pidlRoot);
356  }
357  else
358  {
359  // Anything else is part of the target path to browse to
360  TRACE("CmdLine Parser: Found target path %S\n", strField);
361 
362  // Which can be a shared-memory itemidlist
363  if (!StrCmpIW(strField, L"/IDLIST"))
364  {
365  LPITEMIDLIST pidlArg;
366 
367  if (!hasNext)
368  return FALSE;
369 
370  hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
371  pidlArg = _ILReadFromSharedMemory(strField);
372  if (!pidlArg)
373  return FALSE;
374 
375  if (pInfo->pidlPath)
376  ILFree(pInfo->pidlPath);
377  pInfo->pidlPath = pidlArg;
378 
379  TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, pidlPath=%p\n", pInfo->dwFlags, pInfo->pidlPath);
380  }
381  else
382  {
383  // Or just a plain old string.
384 
385  if (PathIsDirectoryW(strField))
386  PathAddBackslash(strField);
387 
390 
391  if (result != 0 && result <= _countof(szPath) && PathFileExistsW(szPath))
392  StringCchCopyW(strField, _countof(strField), szPath);
393 
394  LPITEMIDLIST pidlPath = ILCreateFromPathW(strField);
395 
396  pInfo->pidlPath = pidlPath;
397 
398  if (pidlPath)
399  {
401  TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, pidlPath=%p\n", pInfo->dwFlags, pInfo->pidlPath);
402  }
403  else
404  {
405  // The path could not be parsed into an ID List,
406  // so pass it on as a plain string.
407 
408  PWSTR field = StrDupW(strField);
409  pInfo->strPath = field;
410  if (field)
411  {
413  TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, strPath=%S\n", pInfo->dwFlags, field);
414  }
415  }
416 
417  }
418  }
419 
420  if (!hasNext)
421  break;
422  hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
423  }
424 
425  return TRUE;
426 }
#define SH_EXPLORER_CMDLINE_FLAG_S
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1702
static PCWSTR _FindFirstField(PCWSTR strFieldSource)
const uint16_t * PCWSTR
Definition: typedefs.h:55
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3835
#define TRUE
Definition: types.h:120
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:925
HRESULT hr
Definition: shlfolder.c:183
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define CSIDL_DESKTOP
Definition: shlobj.h:2003
uint16_t * PWSTR
Definition: typedefs.h:54
#define _countof(array)
Definition: fontsub.cpp:30
static BOOL _ReadNextArg(PCWSTR *pstrFieldSource, PWSTR strField, size_t cchField)
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
#define SH_EXPLORER_CMDLINE_FLAG_ONE
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
#define SH_EXPLORER_CMDLINE_FLAG_IDLIST
LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
Definition: string.c:1089
#define SH_EXPLORER_CMDLINE_FLAG_INPROC
UINT WINAPI GetWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2351
#define CSIDL_MYDOCUMENTS
Definition: shlobj.h:2015
const GUID * guid
BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
Definition: path.c:728
unsigned int BOOL
Definition: ntddk_ex.h:94
LPWSTR WINAPI GetCommandLineW(VOID)
Definition: proc.c:2043
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
#define SH_EXPLORER_CMDLINE_FLAG_E
#define PathAddBackslash
Definition: shlwapi.h:783
smooth NULL
Definition: ftsmooth.c:416
#define _Out_
Definition: no_sal2.h:323
BOOL WINAPI GUIDFromStringW(_In_ PCWSTR psz, _Out_ LPGUID pguid)
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1756
#define SH_EXPLORER_CMDLINE_FLAG_N
LPWSTR WINAPI CharNextW(_In_ LPCWSTR)
#define IntToPtr(i)
Definition: basetsd.h:89
LPWSTR WINAPI CharPrevW(_In_ LPCWSTR, _In_ LPCWSTR)
#define TRACE(s)
Definition: solgame.cpp:4
HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
__wchar_t WCHAR
Definition: xmlstorage.h:180
Definition: parser.c:43
HRESULT WINAPI SHGetSpecialFolderLocation(HWND hwndOwner, INT nFolder, LPITEMIDLIST *ppidl)
Definition: shellpath.c:2687
LONG HRESULT
Definition: typedefs.h:77
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
UINT_PTR WINAPI SHExplorerParseCmdLine(ExplorerCommandLineParseResults *pInfo)
BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:262
static HRESULT _ParsePathToPidl(PWSTR strPath, LPITEMIDLIST *pidl)
int ret
#define SH_EXPLORER_CMDLINE_FLAG_EMBED
static const WCHAR L[]
Definition: oid.c:1250
#define _In_
Definition: no_sal2.h:204
#define SH_EXPLORER_CMDLINE_FLAG_NOUI
#define SH_EXPLORER_CMDLINE_FLAG_STRING
LPCWSTR szPath
Definition: env.c:35
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:228
LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath)
Definition: path.c:501
static LPITEMIDLIST _GetDocumentsPidl()
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:210
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
Definition: string.c:468
INT WINAPI StrToIntW(LPCWSTR lpString)
Definition: string.c:411
BOOL WINAPI SHUnlockShared(LPVOID lpView)
Definition: ordinal.c:242
static LPITEMIDLIST _ILReadFromSharedMemory(PCWSTR strField)
LPITEMIDLIST WINAPI ILCreateFromPathW(LPCWSTR path)
Definition: pidl.c:982
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static BOOL _CopyAndUnquoteText(LPCWSTR strFieldSource, LPWSTR strField, size_t cchField)
GLuint64EXT * result
Definition: glext.h:11304
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
#define SH_EXPLORER_CMDLINE_FLAG_SEPARATE
int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
Definition: string.c:353
#define SH_EXPLORER_CMDLINE_FLAG_SELECT
#define SUCCEEDED(hr)
Definition: intsafe.h:57
static BOOL _FindNextArg(PCWSTR *pstrFieldSource)