ReactOS 0.4.15-dev-7704-gc07eb9f
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
24extern "C"
26 _In_ PCWSTR psz,
27 _Out_ LPGUID pguid
28 );
29
30static 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
102static 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
130static 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
162static 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{
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// Returns FALSE, TRUE or an address.
229extern "C"
231WINAPI
233{
234 WCHAR strField[MAX_PATH];
235 WCHAR strDir[MAX_PATH];
236
237 PCWSTR strCmdLine = GetCommandLineW();
238 PCWSTR strFieldArray = PathGetArgsW(strCmdLine);
239
240 if (!*strFieldArray)
241 {
242 pInfo->dwFlags = 9;
243 pInfo->pidlPath = _GetDocumentsPidl();
244 if (!pInfo->pidlPath)
245 {
247 PathStripToRootW(strDir);
248 pInfo->pidlPath = ILCreateFromPathW(strDir);
249 }
250 return (UINT_PTR)pInfo->pidlPath;
251 }
252
253 PCWSTR strNextArg = _FindFirstField(strFieldArray);
254
255 BOOL hasNext = TRUE;
256
257 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
258 while (TRUE)
259 {
260 // Basic flags-only params first
261 if (!StrCmpIW(strField, L"/N"))
262 {
264 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
265 }
266 else if (!StrCmpIW(strField, L"/S"))
267 {
268 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_S;
269 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
270 }
271 else if (!StrCmpIW(strField, L"/E"))
272 {
273 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_E;
274 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
275 }
276 else if (!StrCmpIW(strField, L"/SELECT"))
277 {
278 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_SELECT;
279 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
280 }
281 else if (!StrCmpIW(strField, L"/NOUI"))
282 {
283 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_NOUI;
284 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
285 }
286 else if (!StrCmpIW(strField, L"-embedding"))
287 {
288 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_EMBED;
289 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
290 }
291 else if (!StrCmpIW(strField, L"/SEPARATE"))
292 {
293 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_SEPARATE;
294 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
295 }
296 else if (!StrCmpIW(strField, L"/INPROC"))
297 {
298 // No idea what Inproc is supposed to do, but it gets a GUID, and parses it.
299
300 TRACE("CmdLine Parser: Found %S flag\n", strField);
301
302 if (!hasNext)
303 return FALSE;
304
305 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
306
307 if (!GUIDFromStringW(strField, &(pInfo->guidInproc)))
308 return FALSE;
309
310 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_INPROC;
311
312 TRACE("CmdLine Parser: Parsed /INPROC flag. dwFlags=%08lx, guidInproc=%S\n", pInfo->dwFlags, strField);
313 }
314 else if (!StrCmpIW(strField, L"/ROOT"))
315 {
316 LPITEMIDLIST pidlRoot = NULL;
317
318 // The window should be rooted
319
320 TRACE("CmdLine Parser: Found %S flag\n", strField);
321
322 if (!pInfo->pidlPath)
323 return FALSE;
324
325 if (!hasNext)
326 return FALSE;
327
328 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
329
330 // Root may be a pidl
331 if (!StrCmpIW(strField, L"/IDLIST"))
332 {
333 if (hasNext)
334 {
335 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
336 }
337 pidlRoot = _ILReadFromSharedMemory(strField);
338 }
339 else
340 {
341 // Or just a path string
342 _ParsePathToPidl(strField, &pidlRoot);
343 }
344
345 pInfo->pidlRoot = pidlRoot;
346
347 // The root defaults to the desktop
348 if (!pidlRoot)
349 {
350 if (FAILED(SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &(pInfo->pidlRoot))))
351 pInfo->pidlRoot = NULL;
352 }
353
354 // TODO: Create rooted PIDL from pInfo->pidlPath and pInfo->pidlRoot
355
356 TRACE("CmdLine Parser: Parsed /ROOT flag. dwFlags=%08lx, pidlRoot=%p\n", pInfo->dwFlags, pInfo->pidlRoot);
357 }
358 else
359 {
360 // Anything else is part of the target path to browse to
361 TRACE("CmdLine Parser: Found target path %S\n", strField);
362
363 // Which can be a shared-memory itemidlist
364 if (!StrCmpIW(strField, L"/IDLIST"))
365 {
366 LPITEMIDLIST pidlArg;
367
368 if (!hasNext)
369 return FALSE;
370
371 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
372 pidlArg = _ILReadFromSharedMemory(strField);
373 if (!pidlArg)
374 return FALSE;
375
376 if (pInfo->pidlPath)
377 ILFree(pInfo->pidlPath);
378 pInfo->pidlPath = pidlArg;
379
380 TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, pidlPath=%p\n", pInfo->dwFlags, pInfo->pidlPath);
381 }
382 else
383 {
384 // Or just a plain old string.
385
386 if (PathIsDirectoryW(strField))
387 PathAddBackslash(strField);
388
391
393 StringCchCopyW(strField, _countof(strField), szPath);
394
395 LPITEMIDLIST pidlPath = ILCreateFromPathW(strField);
396
397 pInfo->pidlPath = pidlPath;
398
399 if (pidlPath)
400 {
401 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_IDLIST;
402 TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, pidlPath=%p\n", pInfo->dwFlags, pInfo->pidlPath);
403 }
404 else
405 {
406 // The path could not be parsed into an ID List,
407 // so pass it on as a plain string.
408
409 PWSTR field = StrDupW(strField);
410 pInfo->strPath = field;
411 if (field)
412 {
413 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_STRING;
414 TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, strPath=%S\n", pInfo->dwFlags, field);
415 }
416 }
417
418 }
419 }
420
421 if (!hasNext)
422 break;
423 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
424 }
425
426 return TRUE;
427}
HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
#define IntToPtr(i)
Definition: basetsd.h:89
#define SH_EXPLORER_CMDLINE_FLAG_EMBED
#define SH_EXPLORER_CMDLINE_FLAG_IDLIST
#define SH_EXPLORER_CMDLINE_FLAG_NOUI
#define SH_EXPLORER_CMDLINE_FLAG_N
#define SH_EXPLORER_CMDLINE_FLAG_INPROC
#define SH_EXPLORER_CMDLINE_FLAG_STRING
#define SH_EXPLORER_CMDLINE_FLAG_ONE
#define SH_EXPLORER_CMDLINE_FLAG_SEPARATE
#define SH_EXPLORER_CMDLINE_FLAG_E
#define SH_EXPLORER_CMDLINE_FLAG_SELECT
#define SH_EXPLORER_CMDLINE_FLAG_S
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
INT WINAPI StrToIntW(LPCWSTR lpString)
Definition: string.c:411
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
Definition: string.c:468
#define MAX_PATH
Definition: compat.h:34
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1106
UINT WINAPI GetWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2352
LPWSTR WINAPI GetCommandLineW(VOID)
Definition: proc.c:2013
HRESULT WINAPI SHGetSpecialFolderLocation(HWND hwndOwner, INT nFolder, LPITEMIDLIST *ppidl)
Definition: shellpath.c:3194
PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:255
BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:311
BOOL WINAPI SHUnlockShared(LPVOID lpView)
Definition: ordinal.c:291
BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
Definition: path.c:733
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1777
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1723
LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath)
Definition: path.c:506
int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
Definition: string.c:353
LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
Definition: string.c:1089
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint64EXT * result
Definition: glext.h:11304
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
const GUID * guid
LPCWSTR szPath
Definition: env.c:37
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
#define L(x)
Definition: ntvdm.h:50
UINT_PTR WINAPI SHExplorerParseCmdLine(_Out_ PEXPLORER_CMDLINE_PARSE_RESULTS pInfo)
static LPITEMIDLIST _ILReadFromSharedMemory(PCWSTR strField)
static HRESULT _ParsePathToPidl(PWSTR strPath, LPITEMIDLIST *pidl)
BOOL WINAPI GUIDFromStringW(_In_ PCWSTR psz, _Out_ LPGUID pguid)
static LPITEMIDLIST _GetDocumentsPidl()
static BOOL _FindNextArg(PCWSTR *pstrFieldSource)
static PCWSTR _FindFirstField(PCWSTR strFieldSource)
static BOOL _ReadNextArg(PCWSTR *pstrFieldSource, PWSTR strField, size_t cchField)
static BOOL _CopyAndUnquoteText(LPCWSTR strFieldSource, LPWSTR strField, size_t cchField)
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:228
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:929
LPITEMIDLIST WINAPI ILCreateFromPathW(LPCWSTR path)
Definition: pidl.c:986
HRESULT hr
Definition: shlfolder.c:183
#define CSIDL_MYDOCUMENTS
Definition: shlobj.h:2170
#define CSIDL_DESKTOP
Definition: shlobj.h:2158
#define PathAddBackslash
Definition: shlwapi.h:783
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
#define _countof(array)
Definition: sndvol32.h:68
#define TRACE(s)
Definition: solgame.cpp:4
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
Definition: parser.c:44
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
int ret
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3837
#define WINAPI
Definition: msvc.h:6
LPWSTR WINAPI CharPrevW(_In_ LPCWSTR, _In_ LPCWSTR)
LPWSTR WINAPI CharNextW(_In_ LPCWSTR)
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185