ReactOS 0.4.15-dev-8222-g9164419
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 = _ReadNextArg(&strNextArg, strField, _countof(strField));
256
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 {
267 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_S;
268 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
269 }
270 else if (!StrCmpIW(strField, L"/E"))
271 {
272 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_E;
273 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
274 }
275 else if (!StrCmpIW(strField, L"/SELECT"))
276 {
277 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_SELECT;
278 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
279 }
280 else if (!StrCmpIW(strField, L"/NOUI"))
281 {
282 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_NOUI;
283 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
284 }
285 else if (!StrCmpIW(strField, L"-embedding"))
286 {
287 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_EMBED;
288 TRACE("CmdLine Parser: Parsed %S flag. dwFlags=%08lx\n", strField, pInfo->dwFlags);
289 }
290 else if (!StrCmpIW(strField, L"/SEPARATE"))
291 {
292 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_SEPARATE;
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
309 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_INPROC;
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 (!hasNext)
322 return FALSE;
323
324 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
325
326 // Root may be a pidl
327 if (!StrCmpIW(strField, L"/IDLIST"))
328 {
329 if (hasNext)
330 {
331 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
332 }
333 pidlRoot = _ILReadFromSharedMemory(strField);
334 }
335 else
336 {
337 // Or just a path string
338 _ParsePathToPidl(strField, &pidlRoot);
339 }
340
341 pInfo->pidlRoot = pidlRoot;
342
343 // The root defaults to the desktop
344 if (!pidlRoot)
345 {
346 if (FAILED(SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &(pInfo->pidlRoot))))
347 pInfo->pidlRoot = NULL;
348 }
349
350 // TODO: Create rooted PIDL from pInfo->pidlPath and pInfo->pidlRoot
351
352 TRACE("CmdLine Parser: Parsed /ROOT flag. dwFlags=%08lx, pidlRoot=%p\n", pInfo->dwFlags, pInfo->pidlRoot);
353 }
354 else
355 {
356 // Anything else is part of the target path to browse to
357 TRACE("CmdLine Parser: Found target path %S\n", strField);
358
359 // Which can be a shared-memory itemidlist
360 if (!StrCmpIW(strField, L"/IDLIST"))
361 {
362 LPITEMIDLIST pidlArg;
363
364 if (!hasNext)
365 return FALSE;
366
367 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
368 pidlArg = _ILReadFromSharedMemory(strField);
369 if (!pidlArg)
370 return FALSE;
371
372 if (pInfo->pidlPath)
373 ILFree(pInfo->pidlPath);
374 pInfo->pidlPath = pidlArg;
375
376 TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, pidlPath=%p\n", pInfo->dwFlags, pInfo->pidlPath);
377 }
378 else
379 {
380 // Or just a plain old string.
381
382 if (PathIsDirectoryW(strField))
383 PathAddBackslash(strField);
384
387
389 StringCchCopyW(strField, _countof(strField), szPath);
390
391 LPITEMIDLIST pidlPath = ILCreateFromPathW(strField);
392
393 pInfo->pidlPath = pidlPath;
394
395 if (pidlPath)
396 {
397 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_IDLIST;
398 TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, pidlPath=%p\n", pInfo->dwFlags, pInfo->pidlPath);
399 }
400 else
401 {
402 // The path could not be parsed into an ID List,
403 // so pass it on as a plain string.
404
405 PWSTR field = StrDupW(strField);
406 pInfo->strPath = field;
407 if (field)
408 {
409 pInfo->dwFlags |= SH_EXPLORER_CMDLINE_FLAG_STRING;
410 TRACE("CmdLine Parser: Parsed target path. dwFlags=%08lx, strPath=%S\n", pInfo->dwFlags, field);
411 }
412 }
413 }
414 }
415
416 if (!hasNext)
417 break;
418 hasNext = _ReadNextArg(&strNextArg, strField, _countof(strField));
419 }
420
421 return TRUE;
422}
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:3260
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:1093
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:237
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:940
LPITEMIDLIST WINAPI ILCreateFromPathW(LPCWSTR path)
Definition: pidl.c:997
HRESULT hr
Definition: shlfolder.c:183
#define CSIDL_MYDOCUMENTS
Definition: shlobj.h:2178
#define CSIDL_DESKTOP
Definition: shlobj.h:2166
#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:70
#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