ReactOS 0.4.16-dev-1873-g416c3a5
shlexec.cpp
Go to the documentation of this file.
1/*
2 * Shell Library Functions
3 *
4 * Copyright 1998 Marcus Meissner
5 * Copyright 2002 Eric Pouech
6 * Copyright 2018-2024 Katayama Hirofumi MZ
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23#include "precomp.h"
24#include <winbase_undoc.h>
25#include <undocshell.h>
26
28
30
31#define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)
32
33typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
34 const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out);
35
37{
38 if ((SIZE_T)hInst > 32)
39 return ERROR_SUCCESS;
40 switch ((SIZE_T)hInst)
41 {
42 case SE_ERR_FNF:
43 case SE_ERR_PNF:
45 case SE_ERR_OOM:
46 return (UINT)(SIZE_T)hInst;
47 case SE_ERR_SHARE:
50 case SE_ERR_DDEFAIL:
51 case SE_ERR_DDEBUSY:
52 return ERROR_DDE_FAIL;
55 //case SE_ERR_ASSOCINCOMPLETE: Note: Windows treats this as a success code
56 case SE_ERR_NOASSOC:
58 case 10:
60 case 12:
61 return ERROR_APP_WRONG_OS;
62 case 15:
63 return ERROR_RMODE_APP;
64 case 16:
66 case 20:
67 return ERROR_INVALID_DLL;
68 }
69 return -1;
70}
71
72// Is the current process a rundll32.exe?
74{
75 WCHAR szModule[MAX_PATH];
76 static INT s_bInDllProcess = -1;
77
78 if (s_bInDllProcess != -1)
79 return s_bInDllProcess;
80
81 s_bInDllProcess = GetModuleFileNameW(NULL, szModule, _countof(szModule)) &&
82 (StrStrIW(PathFindFileNameW(szModule), L"rundll") != NULL);
83 return s_bInDllProcess;
84}
85
87{
88 extern HRESULT SH32_InvokeOpenWith(PCWSTR, LPCMINVOKECOMMANDINFO, HANDLE *);
89
90 HANDLE *phProc = (sei.fMask & SEE_MASK_NOCLOSEPROCESS) ? &sei.hProcess : NULL;
91 UINT fCmic = (sei.fMask & SEE_CMIC_COMMON_BASICFLAGS) | CMIC_MASK_FLAG_NO_UI;
92 CMINVOKECOMMANDINFO ici = { sizeof(ici), fCmic, hWndOwner };
93 ici.nShow = SW_SHOW;
94 HRESULT hr = SH32_InvokeOpenWith(sei.lpFile, &ici, phProc);
96 return SUCCEEDED(hr) ? 42 : SE_ERR_NOASSOC;
97}
98
100{
103 return S_FALSE;
106 return pWide->Execute(pSEI);
108#if 0 // TODO
111 {
113 // TODO: Convert the strings
114 hr = pAnsi->Execute(sei);
115 pSEI->hProcess = sei.hProcess;
116 pSEI->hInstApp = sei.hInstApp;
117 }
118#endif
119 return hr;
120}
121
123{
124 // https://devblogs.microsoft.com/oldnewthing/20080910-00/?p=20933 claims hooks
125 // were removed in Vista but this is incorrect, they are disabled by default.
126 // https://groups.google.com/g/microsoft.public.platformsdk.shell/c/ixdOX1--IKk
127 // says they are now controlled by the EnableShellExecuteHooks policy.
128 if (pSEI->fMask & SEE_MASK_NO_HOOKS)
129 return S_FALSE;
131 return S_FALSE;
132
134 HKEY hKey;
136 if (res != ERROR_SUCCESS)
137 return S_FALSE;
138 for (UINT i = 0; hr == S_FALSE; ++i)
139 {
140 WCHAR szClsid[42];
141 DWORD cch = _countof(szClsid);
142 if (RegEnumValueW(hKey, i, szClsid, &cch, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
143 break;
144 hr = InvokeShellExecuteHook(szClsid, pSEI);
145 }
147 return hr;
148}
149
150static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
151{
152 bool firstCharQuote = false;
153 bool quotes_opened = false;
154 bool backslash_encountered = false;
155
156 for (int curArg = 0; curArg <= argNum && *args; ++curArg)
157 {
158 firstCharQuote = false;
159 if (*args == '"')
160 {
161 quotes_opened = true;
162 firstCharQuote = true;
163 args++;
164 }
165
166 while(*args)
167 {
168 if (*args == '\\')
169 {
170 // if we found a backslash then flip the variable
171 backslash_encountered = !backslash_encountered;
172 }
173 else if (*args == '"')
174 {
175 if (quotes_opened)
176 {
177 if (*(args + 1) != '"')
178 {
179 quotes_opened = false;
180 args++;
181 break;
182 }
183 else
184 {
185 args++;
186 }
187 }
188 else
189 {
190 quotes_opened = true;
191 }
192
193 backslash_encountered = false;
194 }
195 else
196 {
197 backslash_encountered = false;
198 if (*args == ' ' && !firstCharQuote)
199 break;
200 }
201
202 if (curArg == argNum)
203 {
204 used++;
205 if (used < len)
206 *res++ = *args;
207 }
208
209 args++;
210 }
211
212 while(*args == ' ')
213 ++args;
214 }
215}
216
217static void ParseTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
218{
219 bool quotes_opened = false;
220 bool backslash_encountered = false;
221
222 for (int curArg = 0; curArg <= argNum && *args; ++curArg)
223 {
224 while(*args)
225 {
226 if (*args == '\\')
227 {
228 // if we found a backslash then flip the variable
229 backslash_encountered = !backslash_encountered;
230 }
231 else if (*args == '"')
232 {
233 if (quotes_opened)
234 {
235 if (*(args + 1) != '"')
236 {
237 quotes_opened = false;
238 }
239 else
240 {
241 args++;
242 }
243 }
244 else
245 {
246 quotes_opened = true;
247 }
248
249 backslash_encountered = false;
250 }
251 else
252 {
253 backslash_encountered = false;
254 if (*args == ' ' && !quotes_opened && curArg != argNum)
255 break;
256 }
257
258 if (curArg == argNum)
259 {
260 used++;
261 if (used < len)
262 *res++ = *args;
263 }
264
265 args++;
266 }
267 }
268}
269
270/***********************************************************************
271 * SHELL_ArgifyW [Internal]
272 *
273 * this function is supposed to expand the escape sequences found in the registry
274 * some diving reported that the following were used:
275 * + %1, %2... seem to report to parameter of index N in ShellExecute pmts
276 * %1 file
277 * %2 printer
278 * %3 driver
279 * %4 port
280 * %I address of a global item ID (explorer switch /idlist)
281 * %L seems to be %1 as long filename followed by the 8+3 variation
282 * %S ???
283 * %W Working directory
284 * %V Use either %L or %W
285 * %* all following parameters (see batfile)
286 *
287 * The way we parse the command line arguments was determined through extensive
288 * testing and can be summed up by the following rules"
289 *
290 * - %2
291 * - if first letter is " break on first non literal " and include any white spaces
292 * - if first letter is NOT " break on first " or white space
293 * - if " is opened any pair of consecutive " results in ONE literal "
294 *
295 * - %~2
296 * - use rules from here http://www.autohotkey.net/~deleyd/parameters/parameters.htm
297 */
298
299static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len, const WCHAR* lpDir)
300{
301 BOOL done = FALSE;
302 BOOL found_p1 = FALSE;
303 PWSTR res = out;
304 DWORD used = 0;
305 bool tildeEffect = false;
306
307 TRACE("Before parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
308 debugstr_w(lpFile), pidl, args);
309
310 while (*fmt)
311 {
312 if (*fmt == '%')
313 {
314 switch (*++fmt)
315 {
316 case '\0':
317 case '%':
318 {
319 used++;
320 if (used < len)
321 *res++ = '%';
322 };
323 break;
324
325 case '*':
326 {
327 if (args)
328 {
329 if (*fmt == '*')
330 {
331 used++;
332 while(*args)
333 {
334 used++;
335 if (used < len)
336 *res++ = *args++;
337 else
338 args++;
339 }
340 used++;
341 break;
342 }
343 }
344 };
345 break;
346
347 case '~':
348
349 case '2':
350 case '3':
351 case '4':
352 case '5':
353 case '6':
354 case '7':
355 case '8':
356 case '9':
357 //case '0':
358 {
359 if (*fmt == '~')
360 {
361 fmt++;
362 tildeEffect = true;
363 }
364
365 if (args)
366 {
367 if (tildeEffect)
368 {
369 ParseTildeEffect(res, args, len, used, *fmt - '2');
370 tildeEffect = false;
371 }
372 else
373 {
375 }
376 }
377 };
378 break;
379
380 case '1':
381 if ((!done || (*fmt == '1')) && lpFile)
382 {
383 SIZE_T filelen = wcslen(lpFile);
384 used += filelen;
385 if (used < len)
386 {
387 wcscpy(res, lpFile);
388 res += filelen;
389 }
390 }
391 found_p1 = TRUE;
392 break;
393
394 /*
395 * IE uses this a lot for activating things such as windows media
396 * player. This is not verified to be fully correct but it appears
397 * to work just fine.
398 */
399 case 'l':
400 case 'L':
401 if (lpFile)
402 {
403 used += wcslen(lpFile);
404 if (used < len)
405 {
406 wcscpy(res, lpFile);
407 res += wcslen(lpFile);
408 }
409 }
410 found_p1 = TRUE;
411 break;
412
413 case 'w':
414 case 'W':
415 if (lpDir)
416 {
417 used += wcslen(lpDir);
418 if (used < len)
419 {
420 wcscpy(res, lpDir);
421 res += wcslen(lpDir);
422 }
423 }
424 break;
425
426 case 'v':
427 case 'V':
428 if (lpFile)
429 {
430 used += wcslen(lpFile);
431 if (used < len)
432 {
433 wcscpy(res, lpFile);
434 res += wcslen(lpFile);
435 }
436 found_p1 = TRUE;
437 }
438 else if (lpDir)
439 {
440 used += wcslen(lpDir);
441 if (used < len)
442 {
443 wcscpy(res, lpDir);
444 res += wcslen(lpDir);
445 }
446 }
447 break;
448
449 case 'i':
450 case 'I':
451 if (pidl)
452 {
453 DWORD chars = 0;
454 /* %p should not exceed 8, maybe 16 when looking forward to 64bit.
455 * allowing a buffer of 100 should more than exceed all needs */
456 WCHAR buf[100];
457 LPVOID pv;
458 HGLOBAL hmem = SHAllocShared(pidl, ILGetSize(pidl), 0);
459 pv = SHLockShared(hmem, 0);
460 chars = swprintf(buf, L":%p", pv);
461
462 if (chars >= ARRAY_SIZE(buf))
463 ERR("pidl format buffer too small!\n");
464
465 used += chars;
466
467 if (used < len)
468 {
469 wcscpy(res, buf);
470 res += chars;
471 }
472 SHUnlockShared(pv);
473 }
474 found_p1 = TRUE;
475 break;
476
477 default:
478 /*
479 * Check if this is an env-variable here...
480 */
481
482 /* Make sure that we have at least one more %.*/
483 if (strchrW(fmt, '%'))
484 {
485 WCHAR tmpBuffer[1024];
486 PWSTR tmpB = tmpBuffer;
487 WCHAR tmpEnvBuff[MAX_PATH];
488 DWORD envRet;
489
490 while (*fmt != '%')
491 *tmpB++ = *fmt++;
492 *tmpB++ = 0;
493
494 TRACE("Checking %s to be an env-var\n", debugstr_w(tmpBuffer));
495
496 envRet = GetEnvironmentVariableW(tmpBuffer, tmpEnvBuff, MAX_PATH);
497 if (envRet == 0 || envRet > MAX_PATH)
498 {
499 used += wcslen(tmpBuffer);
500 if (used < len)
501 {
502 wcscpy( res, tmpBuffer );
503 res += wcslen(tmpBuffer);
504 }
505 }
506 else
507 {
508 used += wcslen(tmpEnvBuff);
509 if (used < len)
510 {
511 wcscpy( res, tmpEnvBuff );
512 res += wcslen(tmpEnvBuff);
513 }
514 }
515 }
516 done = TRUE;
517 break;
518 }
519 /* Don't skip past terminator (catch a single '%' at the end) */
520 if (*fmt != '\0')
521 {
522 fmt++;
523 }
524 }
525 else
526 {
527 used ++;
528 if (used < len)
529 *res++ = *fmt++;
530 else
531 fmt++;
532 }
533 }
534
535 used++;
536 if (res - out < static_cast<int>(len))
537 *res = '\0';
538 else
539 out[len-1] = '\0';
540
541 TRACE("used %i of %i space\n", used, len);
542 if (out_len)
543 *out_len = used;
544
545 TRACE("After parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
546 debugstr_w(lpFile), pidl, args);
547
548 return found_p1;
549}
550
552{
553 STRRET strret;
554 CComPtr<IShellFolder> desktop;
555
556 HRESULT hr = SHGetDesktopFolder(&desktop);
557
558 if (SUCCEEDED(hr))
559 {
560 hr = desktop->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
561
562 if (SUCCEEDED(hr))
563 StrRetToStrNW(pszPath, uOutSize, &strret, pidl);
564 }
565
566 return hr;
567}
568
570{
571 // Explicitly block the shell desktop listview from becoming the owner (IContextMenu calling ShellExecute)
572 HWND hProgman = GetShellWindow();
574 hWnd != hProgman && !IsChild(hProgman, hWnd))
575 {
576 return hWnd;
577 }
578 return NULL;
579}
580
581/*************************************************************************
582 * PromptAndRunProcessAs [Internal]
583 */
584typedef struct _RUNASDLGDATA
585{
592
593static
597{
599 switch (uMsg)
600 {
601 case WM_INITDIALOG:
602 {
607
609 WCHAR fmtbuf[200], buf[_countof(fmtbuf) + _countof(pData->NameBuffer)];
610 DWORD cch = _countof(pData->NameBuffer);
611 if (GetUserNameW(pData->NameBuffer, &cch))
612 {
613 SendMessageW(hCtl, WM_GETTEXT, _countof(fmtbuf), (LPARAM)buf);
614 StringCchPrintfW(fmtbuf, _countof(fmtbuf), buf, L"(%s)"); // Change "Blah blah %s" to "Blah blah (%s)"
615 StringCchPrintfW(buf, _countof(buf), fmtbuf, pData->NameBuffer);
616 SendMessageW(hCtl, WM_SETTEXT, 0, (LPARAM)buf);
618 }
620 return TRUE;
621 }
622
623 case WM_COMMAND:
624 switch (LOWORD(wParam))
625 {
626 case IDCANCEL:
628 break;
629
630 case IDOK:
631 {
634 pData->Name = pData->NameBuffer;
635 pData->Domain = wcsstr(pData->Name, L"\\");
636 if (pData->Domain)
637 {
638 LPWSTR tmp = pData->Domain + 1;
639 pData->Domain[0] = UNICODE_NULL;
640 pData->Domain = pData->Name;
641 pData->Name = tmp;
642 }
646 pData->Name = NULL;
648 break;
649 }
650
651 case IDC_RUNAS_BROWSE:
652 return SHELL_ErrorBox(hwnd, ERROR_NOT_SUPPORTED); // TODO
653 }
654 break;
655 }
656 return FALSE;
657}
658
659static
664 _In_ DWORD CreationFlags,
666 _In_opt_ LPCWSTR Dir,
667 _In_ STARTUPINFOW *pSI,
669{
671 UINT error;
672 INT_PTR dlgret;
674
675again:
678 if (dlgret == IDOK && data.Name)
679 {
680 if (CreateProcessWithLogonW(data.Name, data.Domain, data.Password, data.LogonFlags,
681 NULL, Cmd, CreationFlags, Env, Dir, pSI, pPI))
683 else
685 switch (error)
686 {
695 goto again;
696 }
697 }
698 else if (dlgret == IDOK)
699 {
700 // TODO: Use the Safer API if requested to
701 if (CreateProcessW(NULL, Cmd, NULL, NULL, FALSE, CreationFlags, Env, Dir, pSI, pPI))
703 else
705 }
706 else if (dlgret == IDCANCEL)
707 {
709 pPI->hProcess = NULL;
710 return S_FALSE;
711 }
712 else
713 {
714 pPI->hProcess = NULL;
715 return E_FAIL;
716 }
717 SecureZeroMemory(&data, sizeof(data));
719}
720
721/*************************************************************************
722 * SHELL_ExecuteW [Internal]
723 *
724 */
725static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
726 const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
727{
731 UINT gcdret = 0, lasterror = 0;
732 WCHAR curdir[MAX_PATH];
733 DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
734 const WCHAR *lpDirectory = NULL;
735
736 TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory));
737
738 /* make sure we don't fail the CreateProcess if the calling app passes in
739 * a bad working directory */
740 if (!StrIsNullOrEmpty(psei->lpDirectory))
741 {
744 lpDirectory = psei->lpDirectory;
745 }
746
747 /* ShellExecute specifies the command from psei->lpDirectory
748 * if present. Not from the current dir as CreateProcess does */
749 if (lpDirectory)
750 if ((gcdret = GetCurrentDirectoryW( MAX_PATH, curdir)))
752 ERR("cannot set directory %s\n", debugstr_w(lpDirectory));
753
755 startup.cb = sizeof(STARTUPINFOW);
757 startup.wShowWindow = psei->nShow;
758 if (!(psei->fMask & SEE_MASK_NO_CONSOLE))
759 dwCreationFlags |= CREATE_NEW_CONSOLE;
760 if (psei->fMask & SEE_MASK_FLAG_SEPVDM)
761 dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
762 startup.lpTitle = (LPWSTR)(psei->fMask & (SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE) ? psei->lpClass : NULL);
763
764 if (psei->fMask & SEE_MASK_HASLINKNAME)
765 startup.dwFlags |= STARTF_TITLEISLINKNAME;
766
767 if (psei->fMask & SEE_MASK_HOTKEY)
768 {
769 startup.hStdInput = UlongToHandle(psei->dwHotKey);
770 startup.dwFlags |= STARTF_USEHOTKEY;
771 }
772
773 if (psei->fMask & SEE_MASK_ICON) // hIcon has higher precedence than hMonitor
774 {
775 startup.hStdOutput = psei->hIcon;
776 startup.dwFlags |= STARTF_SHELLPRIVATE;
777 }
778 else if ((psei->fMask & SEE_MASK_HMONITOR) || psei->hwnd)
779 {
780 if (psei->fMask & SEE_MASK_HMONITOR)
781 startup.hStdOutput = psei->hMonitor;
782 else if (psei->hwnd)
783 startup.hStdOutput = MonitorFromWindow(psei->hwnd, MONITOR_DEFAULTTONEAREST);
784 if (startup.hStdOutput)
785 startup.dwFlags |= STARTF_SHELLPRIVATE;
786 }
787
788 BOOL createdProcess;
789 if (psei->lpVerb && !StrCmpIW(L"runas", psei->lpVerb))
790 {
791 HRESULT hr = PromptAndRunProcessAs(psei->hwnd, (LPWSTR)lpCmd, dwCreationFlags,
793 createdProcess = hr == S_OK;
794 if (hr == S_FALSE)
795 {
796 retval = 33; // Pretend cancel is success.
797 goto done;
798 }
799 }
800 else
801 {
802 createdProcess = CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE,
803 dwCreationFlags, env, lpDirectory, &startup, &info);
804 }
805
806 if (createdProcess)
807 {
808 /* Give 30 seconds to the app to come up, if desired. Probably only needed
809 when starting app immediately before making a DDE connection. */
810 if (shWait)
811 if (WaitForInputIdle(info.hProcess, 30000) == WAIT_FAILED)
812 WARN("WaitForInputIdle failed: Error %d\n", GetLastError() );
813 retval = 33;
814
815 if (psei->fMask & SEE_MASK_NOCLOSEPROCESS)
816 psei_out->hProcess = info.hProcess;
817 else
818 CloseHandle( info.hProcess );
819 CloseHandle( info.hThread );
820 }
821 else if ((retval = lasterror = GetLastError()) >= 32)
822 {
823 WARN("CreateProcess returned error %ld\n", retval);
825 }
826
827done:
828 TRACE("returning %lu\n", retval);
829 psei_out->hInstApp = (HINSTANCE)retval;
830
831 if (gcdret)
832 {
833 if (!SetCurrentDirectoryW(curdir))
834 ERR("cannot return to directory %s\n", debugstr_w(curdir));
835 if (lasterror)
836 RestoreLastError(lasterror);
837 }
838 return retval;
839}
840
841
842/***********************************************************************
843 * SHELL_BuildEnvW [Internal]
844 *
845 * Build the environment for the new process, adding the specified
846 * path to the PATH variable. Returned pointer must be freed by caller.
847 */
849{
851 WCHAR *strings, *p, *p2;
852 int total = wcslen(path) + 1;
853 BOOL got_path = FALSE;
854
855 if (!(strings = GetEnvironmentStringsW())) return NULL;
856 p = strings;
857 while (*p)
858 {
859 int len = wcslen(p) + 1;
860 if (!_wcsnicmp( p, L"PATH=", 5 )) got_path = TRUE;
861 total += len;
862 p += len;
863 }
864 if (!got_path) total += 5; /* we need to create PATH */
865 total++; /* terminating null */
866
867 if (!new_env.Allocate(total))
868 {
870 return NULL;
871 }
872 p = strings;
873 p2 = new_env;
874 while (*p)
875 {
876 int len = wcslen(p) + 1;
877 memcpy(p2, p, len * sizeof(WCHAR));
878 if (!_wcsnicmp( p, L"PATH=", 5 ))
879 {
880 p2[len - 1] = ';';
881 wcscpy( p2 + len, path );
882 p2 += wcslen(path) + 1;
883 }
884 p += len;
885 p2 += len;
886 }
887 if (!got_path)
888 {
889 wcscpy(p2, L"PATH=");
890 wcscat(p2, path);
891 p2 += wcslen(p2) + 1;
892 }
893 *p2 = 0;
895 return new_env.Detach();
896}
897
898/***********************************************************************
899 * SHELL_TryAppPathW [Internal]
900 *
901 * Helper function for SHELL_FindExecutable
902 * @param lpResult - pointer to a buffer of size MAX_PATH
903 * On entry: szName is a filename (probably without path separators).
904 * On exit: if szName found in "App Path", place full path in lpResult, and return true
905 */
907{
908 HKEY hkApp = NULL;
909 WCHAR buffer[1024];
910 DWORD len, dwType;
911 LONG res;
912 BOOL found = FALSE;
913
914 if (env) *env = NULL;
915 wcscpy(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
918 if (res)
919 {
920 // Add ".exe" extension, if extension does not exists
921 if (PathAddExtensionW(buffer, L".exe"))
922 {
924 }
925 if (res) goto end;
926 }
927
928 len = MAX_PATH * sizeof(WCHAR);
929 res = SHRegQueryValueExW(hkApp, NULL, NULL, &dwType, (LPBYTE)lpResult, &len);
930 if (res != ERROR_SUCCESS || dwType != REG_SZ)
931 goto end;
932
933 found = TRUE;
934
935 if (env)
936 {
937 len = sizeof(buffer);
938 res = SHRegQueryValueExW(hkApp, L"Path", NULL, &dwType, (LPBYTE)buffer, &len);
939 if (res == ERROR_SUCCESS && dwType == REG_SZ && buffer[0])
941 }
942
943end:
944 if (hkApp) RegCloseKey(hkApp);
945 return found;
946}
947
948/*************************************************************************
949 * SHELL_FindExecutableByVerb [Internal]
950 *
951 * called from SHELL_FindExecutable or SHELL_execute_class
952 * in/out:
953 * classname a buffer, big enough, to get the key name to do actually the
954 * command "WordPad.Document.1\\shell\\open\\command"
955 * passed as "WordPad.Document.1"
956 * in:
957 * lpVerb the operation on it (open)
958 * commandlen the size of command buffer (in bytes)
959 * out:
960 * command a buffer, to store the command to do the
961 * operation on the file
962 * key a buffer, big enough, to get the key name to do actually the
963 * command "WordPad.Document.1\\shell\\open\\command"
964 * Can be NULL
965 */
967{
968 HKEY hkeyClass;
969 WCHAR verb[MAX_PATH];
970
972 return SE_ERR_NOASSOC;
973 if (!HCR_GetDefaultVerbW(hkeyClass, lpVerb, verb, ARRAY_SIZE(verb)))
974 return SE_ERR_NOASSOC;
975 RegCloseKey(hkeyClass);
976
977 /* Looking for ...buffer\shell<verb>\command */
978 wcscat(classname, L"\\shell\\"); // FIXME: Use HCR_GetExecuteCommandW or AssocAPI
979 wcscat(classname, verb);
980 wcscat(classname, L"\\command");
981
983 &commandlen) == ERROR_SUCCESS)
984 {
985 commandlen /= sizeof(WCHAR);
986 if (key) wcscpy(key, classname);
987#if 0
988 LPWSTR tmp;
989 WCHAR param[256];
990 LONG paramlen = sizeof(param);
991
992 /* FIXME: it seems all Windows version don't behave the same here.
993 * the doc states that this ddeexec information can be found after
994 * the exec names.
995 * on Win98, it doesn't appear, but I think it does on Win2k
996 */
997 /* Get the parameters needed by the application
998 from the associated ddeexec key */
999 tmp = strstrW(classname, L"\\command");
1000 tmp[0] = '\0';
1001 wcscat(classname, wDdeexec);
1003 &paramlen) == ERROR_SUCCESS)
1004 {
1005 paramlen /= sizeof(WCHAR);
1006 wcscat(command, L" ");
1008 commandlen += paramlen;
1009 }
1010#endif
1011
1012 command[commandlen] = '\0';
1013
1014 return 33; /* FIXME see SHELL_FindExecutable() */
1015 }
1016
1017 return SE_ERR_NOASSOC;
1018}
1019
1020/*************************************************************************
1021 * SHELL_FindExecutable [Internal]
1022 *
1023 * Utility for code sharing between FindExecutable and ShellExecute
1024 * in:
1025 * lpFile the name of a file
1026 * lpVerb the operation on it (open)
1027 * out:
1028 * lpResult a buffer, big enough :-(, to store the command to do the
1029 * operation on the file
1030 * key a buffer, big enough, to get the key name to do actually the
1031 * command (it'll be used afterwards for more information
1032 * on the operation)
1033 */
1034static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb,
1035 LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args)
1036{
1037 WCHAR *extension = NULL; /* pointer to file extension */
1038 WCHAR classname[256]; /* registry name for this file type */
1039 LONG classnamelen = sizeof(classname); /* length of above */
1040 WCHAR command[1024]; /* command from registry */
1041 WCHAR wBuffer[256]; /* Used to GetProfileString */
1043 WCHAR *tok; /* token pointer */
1044 WCHAR xlpFile[MAX_PATH]; /* result of PathResolve */
1045 DWORD attribs; /* file attributes */
1046 WCHAR curdir[MAX_PATH];
1047 const WCHAR *search_paths[3] = {0};
1048
1049 TRACE("%s\n", debugstr_w(lpFile));
1050
1051 if (!lpResult)
1053
1054 xlpFile[0] = '\0';
1055 lpResult[0] = '\0'; /* Start off with an empty return string */
1056 if (key) *key = '\0';
1057
1058 /* trap NULL parameters on entry */
1059 if (!lpFile)
1060 {
1061 WARN("(lpFile=%s,lpResult=%s): NULL parameter\n",
1062 debugstr_w(lpFile), debugstr_w(lpResult));
1063 return ERROR_FILE_NOT_FOUND; /* File not found. Close enough, I guess. */
1064 }
1065
1066 if (SHELL_TryAppPathW( lpFile, lpResult, env ))
1067 {
1068 TRACE("found %s via App Paths\n", debugstr_w(lpResult));
1069 return 33;
1070 }
1071
1072 GetCurrentDirectoryW(ARRAY_SIZE(curdir), curdir);
1073 if (lpPath && *lpPath)
1074 {
1075 search_paths[0] = lpPath;
1076 search_paths[1] = curdir;
1077 }
1078 else
1079 {
1080 search_paths[0] = curdir;
1081 }
1082
1083 lstrcpyW(xlpFile, lpFile);
1084 if (PathResolveW(xlpFile, search_paths, PRF_TRYPROGRAMEXTENSIONS | PRF_VERIFYEXISTS) ||
1085 PathFindOnPathW(xlpFile, search_paths))
1086 {
1087 TRACE("PathResolveW returned non-zero\n");
1088 lpFile = xlpFile;
1089 PathRemoveBlanksW(xlpFile);
1090
1091 /* Clear any trailing periods */
1092 SIZE_T i = wcslen(xlpFile);
1093 while (i > 0 && xlpFile[i - 1] == '.')
1094 {
1095 xlpFile[--i] = '\0';
1096 }
1097
1098 lstrcpyW(lpResult, xlpFile);
1099 /* The file was found in lpPath or one of the directories in the system-wide search path */
1100 }
1101 else
1102 {
1103 xlpFile[0] = '\0';
1104 }
1105
1106 attribs = GetFileAttributesW(lpFile);
1108 {
1109 wcscpy(classname, L"Folder");
1110 }
1111 else
1112 {
1113 /* Did we get something? Anything? */
1114 if (xlpFile[0] == 0)
1115 {
1116 TRACE("Returning SE_ERR_FNF\n");
1117 return SE_ERR_FNF;
1118 }
1119 /* First thing we need is the file's extension */
1120 extension = wcsrchr(xlpFile, '.'); /* Assume last "." is the one; */
1121 /* File->Run in progman uses */
1122 /* .\FILE.EXE :( */
1123 TRACE("xlpFile=%s,extension=%s\n", debugstr_w(xlpFile), debugstr_w(extension));
1124
1125 if (extension == NULL || extension[1] == 0)
1126 {
1127 WARN("Returning SE_ERR_NOASSOC\n");
1128 return SE_ERR_NOASSOC;
1129 }
1130
1131 /* Three places to check: */
1132 /* 1. win.ini, [windows], programs (NB no leading '.') */
1133 /* 2. Registry, HKEY_CLASS_ROOT<classname>\shell\open\command */
1134 /* 3. win.ini, [extensions], extension (NB no leading '.' */
1135 /* All I know of the order is that registry is checked before */
1136 /* extensions; however, it'd make sense to check the programs */
1137 /* section first, so that's what happens here. */
1138
1139 /* See if it's a program - if GetProfileString fails, we skip this
1140 * section. Actually, if GetProfileString fails, we've probably
1141 * got a lot more to worry about than running a program... */
1142 if (GetProfileStringW(L"windows", L"programs", L"exe pif bat cmd com", wBuffer, ARRAY_SIZE(wBuffer)) > 0)
1143 {
1144 CharLowerW(wBuffer);
1145 tok = wBuffer;
1146 while (*tok)
1147 {
1148 WCHAR *p = tok;
1149 while (*p && *p != ' ' && *p != '\t') p++;
1150 if (*p)
1151 {
1152 *p++ = 0;
1153 while (*p == ' ' || *p == '\t') p++;
1154 }
1155
1156 if (_wcsicmp(tok, &extension[1]) == 0) /* have to skip the leading "." */
1157 {
1158 wcscpy(lpResult, xlpFile);
1159 /* Need to perhaps check that the file has a path
1160 * attached */
1161 TRACE("found %s\n", debugstr_w(lpResult));
1162 return 33;
1163 /* Greater than 32 to indicate success */
1164 }
1165 tok = p;
1166 }
1167 }
1168
1169 /* Check registry */
1171 &classnamelen) == ERROR_SUCCESS)
1172 {
1173 classnamelen /= sizeof(WCHAR);
1174 if (classnamelen == ARRAY_SIZE(classname))
1175 classnamelen--;
1176
1177 classname[classnamelen] = '\0';
1178 TRACE("File type: %s\n", debugstr_w(classname));
1179 }
1180 else
1181 {
1182 *classname = '\0';
1183 }
1184 }
1185
1186 if (*classname)
1187 {
1188 /* pass the verb string to SHELL_FindExecutableByVerb() */
1190
1191 if (retval > 32)
1192 {
1193 DWORD finishedLen;
1194 SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen, lpPath);
1195 if (finishedLen > resultLen)
1196 ERR("Argify buffer not large enough.. truncated\n");
1197 /* Remove double quotation marks and command line arguments */
1198 if (*lpResult == '"')
1199 {
1200 WCHAR *p = lpResult;
1201 while (*(p + 1) != '"')
1202 {
1203 *p = *(p + 1);
1204 p++;
1205 }
1206 *p = '\0';
1207 }
1208 else
1209 {
1210 /* Truncate on first space */
1211 WCHAR *p = lpResult;
1212 while (*p != ' ' && *p != '\0')
1213 p++;
1214 *p = '\0';
1215 }
1216 }
1217 }
1218 else /* Check win.ini */
1219 {
1220 /* Toss the leading dot */
1221 extension++;
1222 if (GetProfileStringW(L"extensions", extension, L"", command, ARRAY_SIZE(command)) > 0)
1223 {
1224 if (wcslen(command) != 0)
1225 {
1226 wcscpy(lpResult, command);
1227 tok = wcschr(lpResult, '^'); /* should be ^.extension? */
1228 if (tok != NULL)
1229 {
1230 tok[0] = '\0';
1231 wcscat(lpResult, xlpFile); /* what if no dir in xlpFile? */
1232 tok = wcschr(command, '^'); /* see above */
1233 if ((tok != NULL) && (wcslen(tok) > 5))
1234 {
1235 wcscat(lpResult, &tok[5]);
1236 }
1237 }
1238 retval = 33; /* FIXME - see above */
1239 }
1240 }
1241 }
1242
1243 TRACE("returning path %s, retval %d\n", debugstr_w(lpResult), retval);
1244 return retval;
1245}
1246
1247/******************************************************************
1248 * dde_cb
1249 *
1250 * callback for the DDE connection. not really useful
1251 */
1252static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv,
1253 HSZ hsz1, HSZ hsz2, HDDEDATA hData,
1254 ULONG_PTR dwData1, ULONG_PTR dwData2)
1255{
1256 TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
1257 uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
1258 return NULL;
1259}
1260
1261/******************************************************************
1262 * dde_connect
1263 *
1264 * ShellExecute helper. Used to do an operation with a DDE connection
1265 *
1266 * Handles both the direct connection (try #1), and if it fails,
1267 * launching an application and trying (#2) to connect to it
1268 *
1269 */
1270static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec,
1271 const WCHAR* lpFile, WCHAR *env,
1272 LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc,
1273 const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
1274{
1275 WCHAR regkey[256];
1276 WCHAR * endkey = regkey + wcslen(key);
1277 WCHAR app[256], topic[256], ifexec[256], static_res[256];
1279 WCHAR * res;
1280 LONG applen, topiclen, ifexeclen;
1281 WCHAR * exec;
1282 DWORD ddeInst = 0;
1283 DWORD tid;
1284 DWORD resultLen, endkeyLen;
1285 HSZ hszApp, hszTopic;
1286 HCONV hConv;
1287 HDDEDATA hDdeData;
1288 unsigned ret = SE_ERR_NOASSOC;
1289 BOOL unicode = !(GetVersion() & 0x80000000);
1290
1291 if (strlenW(key) + 1 > ARRAY_SIZE(regkey))
1292 {
1293 FIXME("input parameter %s larger than buffer\n", debugstr_w(key));
1294 return 2;
1295 }
1296 wcscpy(regkey, key);
1297 endkeyLen = ARRAY_SIZE(regkey) - (endkey - regkey);
1298 if (strlenW(L"\\application") + 1 > endkeyLen)
1299 {
1300 FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\application"));
1301 return 2;
1302 }
1303 wcscpy(endkey, L"\\application");
1304 applen = sizeof(app);
1305 if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, app, &applen) != ERROR_SUCCESS)
1306 {
1307 WCHAR command[1024], fullpath[MAX_PATH];
1308 LPWSTR ptr = NULL;
1309 DWORD ret = 0;
1310
1311 /* Get application command from start string and find filename of application */
1312 if (*start == '"')
1313 {
1314 if (strlenW(start + 1) + 1 > ARRAY_SIZE(command))
1315 {
1316 FIXME("size of input parameter %s larger than buffer\n",
1317 debugstr_w(start + 1));
1318 return 2;
1319 }
1320 wcscpy(command, start + 1);
1321 if ((ptr = wcschr(command, '"')))
1322 * ptr = 0;
1323 ret = SearchPathW(NULL, command, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr);
1324 }
1325 else
1326 {
1327 LPCWSTR p;
1328 LPWSTR space;
1329 for (p = start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1)
1330 {
1331 int idx = space - start;
1332 memcpy(command, start, idx * sizeof(WCHAR));
1333 command[idx] = '\0';
1334 if ((ret = SearchPathW(NULL, command, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr)))
1335 break;
1336 }
1337 if (!ret)
1338 ret = SearchPathW(NULL, start, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr);
1339 }
1340
1341 if (!ret)
1342 {
1343 ERR("Unable to find application path for command %s\n", debugstr_w(start));
1344 return ERROR_ACCESS_DENIED;
1345 }
1346 if (strlenW(ptr) + 1 > ARRAY_SIZE(app))
1347 {
1348 FIXME("size of found path %s larger than buffer\n", debugstr_w(ptr));
1349 return 2;
1350 }
1351 wcscpy(app, ptr);
1352
1353 /* Remove extensions (including .so) */
1354 ptr = app + wcslen(app) - 3;
1355 if (ptr > app && !wcscmp(ptr, L".so"))
1356 *ptr = 0;
1357
1358 ptr = const_cast<LPWSTR>(strrchrW(app, '.'));
1359 assert(ptr);
1360 *ptr = 0;
1361 }
1362
1363 if (strlenW(L"\\topic") + 1 > endkeyLen)
1364 {
1365 FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\topic"));
1366 return 2;
1367 }
1368 wcscpy(endkey, L"\\topic");
1369 topiclen = sizeof(topic);
1370 if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS)
1371 {
1372 wcscpy(topic, L"System");
1373 }
1374
1375 if (unicode)
1376 {
1378 return 2;
1379 }
1380 else
1381 {
1383 return 2;
1384 }
1385
1388
1389 hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
1390 exec = ddeexec;
1391 if (!hConv)
1392 {
1393 TRACE("Launching %s\n", debugstr_w(start));
1394 ret = execfunc(start, env, TRUE, psei, psei_out);
1395 if (ret <= 32)
1396 {
1397 TRACE("Couldn't launch\n");
1398 goto error;
1399 }
1400 /* if ddeexec is NULL, then we just need to exit here */
1401 if (ddeexec == NULL)
1402 {
1403 TRACE("Exiting because ddeexec is NULL. ret=42.\n");
1404 /* See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew */
1405 /* for reason why we use 42 here and also "Shell32_apitest ShellExecuteW" regression test */
1406 return 42;
1407 }
1408 /* if ddeexec is 'empty string', then we just need to exit here */
1409 if (wcscmp(ddeexec, L"") == 0)
1410 {
1411 TRACE("Exiting because ddeexec is 'empty string'. ret=42.\n");
1412 /* See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew */
1413 /* for reason why we use 42 here and also "Shell32_apitest ShellExecuteW" regression test */
1414 return 42;
1415 }
1416 hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
1417 if (!hConv)
1418 {
1419 TRACE("Couldn't connect. ret=%d\n", ret);
1422 return 30; /* whatever */
1423 }
1424 if (strlenW(L"\\ifexec") + 1 > endkeyLen)
1425 {
1426 FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\ifexec"));
1427 return 2;
1428 }
1429 strcpyW(endkey, L"\\ifexec");
1430 ifexeclen = sizeof(ifexec);
1431 if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS)
1432 {
1433 exec = ifexec;
1434 }
1435 }
1436
1437 SHELL_ArgifyW(static_res, ARRAY_SIZE(static_res), exec, lpFile, pidl, szCommandline, &resultLen, NULL);
1438 if (resultLen > ARRAY_SIZE(static_res))
1439 {
1440 dynamic_res.Allocate(resultLen);
1441 res = dynamic_res;
1442 SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL, NULL);
1443 }
1444 else
1445 res = static_res;
1446 TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res));
1447
1448 /* It's documented in the KB 330337 that IE has a bug and returns
1449 * error DMLERR_NOTPROCESSED on XTYP_EXECUTE request.
1450 */
1451 if (unicode)
1452 hDdeData = DdeClientTransaction((LPBYTE)res, (strlenW(res) + 1) * sizeof(WCHAR), hConv, 0L, 0, XTYP_EXECUTE, 30000, &tid);
1453 else
1454 {
1455 DWORD lenA = WideCharToMultiByte(CP_ACP, 0, res, -1, NULL, 0, NULL, NULL);
1457 resA.Allocate(lenA);
1458 WideCharToMultiByte(CP_ACP, 0, res, -1, resA, lenA, NULL, NULL);
1459 hDdeData = DdeClientTransaction( (LPBYTE)(LPSTR)resA, lenA, hConv, 0L, 0,
1460 XTYP_EXECUTE, 10000, &tid );
1461 }
1462 if (hDdeData)
1463 DdeFreeDataHandle(hDdeData);
1464 else
1465 WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst));
1466 ret = 33;
1467
1468 DdeDisconnect(hConv);
1469
1470error:
1472
1473 return ret;
1474}
1475
1476/*************************************************************************
1477 * execute_from_key [Internal]
1478 */
1480 LPCWSTR szCommandline, LPCWSTR executable_name,
1481 SHELL_ExecuteW32 execfunc,
1483{
1484 WCHAR cmd[256], param[1024], ddeexec[256];
1485 DWORD cmdlen = sizeof(cmd), ddeexeclen = sizeof(ddeexec);
1487 DWORD resultLen;
1488 LPWSTR tmp;
1489
1490 TRACE("%s %s %s %s %s\n", debugstr_w(key), debugstr_w(lpFile), debugstr_w(env),
1491 debugstr_w(szCommandline), debugstr_w(executable_name));
1492
1493 cmd[0] = '\0';
1494 param[0] = '\0';
1495
1496 /* Get the application from the registry */
1498 {
1499 TRACE("got cmd: %s\n", debugstr_w(cmd));
1500
1501 /* Is there a replace() function anywhere? */
1502 cmdlen /= sizeof(WCHAR);
1503 if (cmdlen >= ARRAY_SIZE(cmd))
1504 cmdlen = ARRAY_SIZE(cmd) - 1;
1505 cmd[cmdlen] = '\0';
1506 SHELL_ArgifyW(param, ARRAY_SIZE(param), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen,
1507 (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL);
1508 if (resultLen > ARRAY_SIZE(param))
1509 ERR("Argify buffer not large enough, truncating\n");
1510 }
1511
1512 /* Get the parameters needed by the application
1513 from the associated ddeexec key */
1514 tmp = const_cast<LPWSTR>(strstrW(key, L"command"));
1515 assert(tmp);
1516 wcscpy(tmp, L"ddeexec");
1517
1518 if (RegQueryValueW(HKEY_CLASSES_ROOT, key, ddeexec, (LONG *)&ddeexeclen) == ERROR_SUCCESS)
1519 {
1520 TRACE("Got ddeexec %s => %s\n", debugstr_w(key), debugstr_w(ddeexec));
1521 if (!param[0]) strcpyW(param, executable_name);
1522 retval = dde_connect(key, param, ddeexec, lpFile, env, szCommandline, (LPITEMIDLIST)psei->lpIDList, execfunc, psei, psei_out);
1523 }
1524 else if (param[0])
1525 {
1526 TRACE("executing: %s\n", debugstr_w(param));
1527 retval = execfunc(param, env, FALSE, psei, psei_out);
1528 }
1529 else
1530 WARN("Nothing appropriate found for %s\n", debugstr_w(key));
1531
1532 return retval;
1533}
1534
1535/*************************************************************************
1536 * FindExecutableA [SHELL32.@]
1537 */
1539{
1541 WCHAR *wFile = NULL, *wDirectory = NULL;
1542 WCHAR wResult[MAX_PATH];
1543
1544 if (lpFile) __SHCloneStrAtoW(&wFile, lpFile);
1545 if (lpDirectory) __SHCloneStrAtoW(&wDirectory, lpDirectory);
1546
1547 retval = FindExecutableW(wFile, wDirectory, wResult);
1548 WideCharToMultiByte(CP_ACP, 0, wResult, -1, lpResult, MAX_PATH, NULL, NULL);
1549 SHFree(wFile);
1550 SHFree(wDirectory);
1551
1552 TRACE("returning %s\n", lpResult);
1553 return retval;
1554}
1555
1556/*************************************************************************
1557 * FindExecutableW [SHELL32.@]
1558 *
1559 * This function returns the executable associated with the specified file
1560 * for the default verb.
1561 *
1562 * PARAMS
1563 * lpFile [I] The file to find the association for. This must refer to
1564 * an existing file otherwise FindExecutable fails and returns
1565 * SE_ERR_FNF.
1566 * lpResult [O] Points to a buffer into which the executable path is
1567 * copied. This parameter must not be NULL otherwise
1568 * FindExecutable() segfaults. The buffer must be of size at
1569 * least MAX_PATH characters.
1570 *
1571 * RETURNS
1572 * A value greater than 32 on success, less than or equal to 32 otherwise.
1573 * See the SE_ERR_* constants.
1574 *
1575 * NOTES
1576 * On Windows XP and 2003, FindExecutable() seems to first convert the
1577 * filename into 8.3 format, thus taking into account only the first three
1578 * characters of the extension, and expects to find an association for those.
1579 * However other Windows versions behave sanely.
1580 */
1582{
1584 WCHAR old_dir[MAX_PATH], res[MAX_PATH];
1585 DWORD cch = _countof(res);
1586 LPCWSTR dirs[2];
1587
1588 TRACE("File %s, Dir %s\n", debugstr_w(lpFile), debugstr_w(lpDirectory));
1589
1590 *lpResult = UNICODE_NULL;
1591
1592 GetCurrentDirectoryW(_countof(old_dir), old_dir);
1593
1594 if (lpDirectory && *lpDirectory)
1595 {
1597 dirs[0] = lpDirectory;
1598 }
1599 else
1600 {
1601 dirs[0] = old_dir;
1602 }
1603 dirs[1] = NULL;
1604
1605 if (!GetShortPathNameW(lpFile, res, _countof(res)))
1606 StringCchCopyW(res, _countof(res), lpFile);
1607
1609 {
1610 // NOTE: The last parameter of this AssocQueryStringW call is "strange" in Windows.
1611 if (PathIsExeW(res) ||
1613 {
1614 StringCchCopyW(lpResult, MAX_PATH, res);
1615 retval = 42;
1616 }
1617 else
1618 {
1620 }
1621 }
1622 else
1623 {
1625 }
1626
1627 TRACE("returning %s\n", debugstr_w(lpResult));
1628 SetCurrentDirectoryW(old_dir);
1629 return (HINSTANCE)retval;
1630}
1631
1632/* FIXME: is this already implemented somewhere else? */
1634{
1636 return sei->hkeyClass;
1637
1638 HKEY hKey = NULL;
1639 if (sei->fMask & SEE_MASK_CLASSNAME)
1640 {
1641 TRACE("class = %s\n", debugstr_w(sei->lpClass));
1643 return hKey;
1644 }
1646 TRACE("ext = %s\n", debugstr_w(ext));
1647 if (!StrIsNullOrEmpty(ext) && SUCCEEDED(HCR_GetProgIdKeyOfExtension(ext, &hKey, FALSE)))
1648 return hKey;
1649 return NULL;
1650}
1651
1653{
1654 CComHeapPtr<ITEMIDLIST> allocatedPidl;
1655 LPITEMIDLIST pidl = NULL;
1656
1657 if (sei->fMask & SEE_MASK_CLASSALL) // FIXME: This makes no sense? SEE_MASK_IDLIST?
1658 {
1659 pidl = (LPITEMIDLIST)sei->lpIDList;
1660 }
1661 else
1662 {
1663 WCHAR fullpath[MAX_PATH];
1664 BOOL ret;
1665
1666 fullpath[0] = 0;
1667 ret = GetFullPathNameW(sei->lpFile, MAX_PATH, fullpath, NULL);
1668 if (!ret)
1670
1671 pidl = ILCreateFromPathW(fullpath);
1672 allocatedPidl.Attach(pidl);
1673 }
1675}
1676
1679{
1681 CMINVOKECOMMANDINFOEX ici;
1683 WCHAR string[0x80];
1684 INT i, n, def = -1;
1685 HMENU hmenu = 0;
1686 HRESULT r;
1687
1688 TRACE("%p %p\n", obj, sei);
1689
1690 r = obj->QueryInterface(IID_PPV_ARG(IContextMenu, &cm));
1691 if (FAILED(r))
1692 return r;
1693
1694 hmenu = CreateMenu();
1695 if (!hmenu)
1696 goto end;
1697
1698 /* the number of the last menu added is returned in r */
1699 r = cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
1700 if (FAILED(r))
1701 goto end;
1702
1704 for (i = 0; i < n; i++)
1705 {
1706 memset(&info, 0, sizeof(info));
1707 info.cbSize = sizeof info;
1709 info.dwTypeData = string;
1710 info.cch = sizeof string;
1711 string[0] = 0;
1713
1714 TRACE("menu %d %s %08x %08lx %08x %08x\n", i, debugstr_w(string),
1715 info.fState, info.dwItemData, info.fType, info.wID);
1716 if ((!sei->lpVerb && (info.fState & MFS_DEFAULT)) ||
1717 (sei->lpVerb && !lstrcmpiW(sei->lpVerb, string)))
1718 {
1719 def = i;
1720 break;
1721 }
1722 }
1723
1724 r = E_FAIL;
1725 if (def == -1)
1726 goto end;
1727
1728 memset(&ici, 0, sizeof ici);
1729 ici.cbSize = sizeof ici;
1730 ici.fMask = (sei->fMask & SEE_CMIC_COMMON_BASICFLAGS) | CMIC_MASK_UNICODE;
1731 ici.nShow = sei->nShow;
1732 ici.lpVerb = MAKEINTRESOURCEA(def);
1733 ici.hwnd = sei->hwnd;
1734 ici.lpParametersW = sei->lpParameters;
1735
1736 r = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
1737
1738 TRACE("invoke command returned %08x\n", r);
1739
1740end:
1741 if (hmenu)
1742 DestroyMenu( hmenu );
1743 return r;
1744}
1745
1747{
1748 TRACE("%p %s %p\n", hkey, debugstr_guid(guid), sei);
1749
1750 CCoInit coInit;
1751
1752 if (FAILED_UNEXPECTEDLY(coInit.hr))
1753 return coInit.hr;
1754
1756 HRESULT hr = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER,
1759 return hr;
1760
1761 CComPtr<IDataObject> dataobj;
1762 hr = shellex_get_dataobj(sei, dataobj);
1764 return hr;
1765
1766 hr = obj->Initialize(NULL, dataobj, hkey);
1768 return hr;
1769
1771 hr = obj->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows));
1773 return hr;
1774
1775 ows->SetSite(NULL);
1776
1778}
1779
1781{
1782 CComHeapPtr<ITEMIDLIST> allocatedPidl;
1783 LPITEMIDLIST pidl = NULL;
1784
1785 if (sei->lpIDList)
1786 {
1787 pidl = (LPITEMIDLIST)sei->lpIDList;
1788 }
1789 else
1790 {
1791 SFGAOF sfga = 0;
1792 HRESULT hr = SHParseDisplayName(sei->lpFile, NULL, &allocatedPidl, SFGAO_STORAGECAPMASK, &sfga);
1793 if (FAILED(hr))
1794 {
1795 WCHAR Buffer[MAX_PATH] = {};
1796 // FIXME: MAX_PATH.....
1798 if (retval <= 32)
1799 return HRESULT_FROM_WIN32(retval);
1800
1801 hr = SHParseDisplayName(Buffer, NULL, &allocatedPidl, SFGAO_STORAGECAPMASK, &sfga);
1802 // This should not happen, we found it...
1804 return hr;
1805 }
1806
1807 pidl = allocatedPidl;
1808 }
1809
1811 LPCITEMIDLIST pidllast = NULL;
1812 HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast);
1813 if (FAILED(hr))
1814 return hr;
1815
1816 return shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IContextMenu, &cm));
1817}
1818
1820{
1821 TRACE("%p\n", sei);
1822
1823 CCoInit coInit;
1824
1825 if (FAILED_UNEXPECTEDLY(coInit.hr))
1826 return coInit.hr;
1827
1831 return hr;
1832
1833 CComHeapPtr<char> verb, parameters, dir;
1834 __SHCloneStrWtoA(&verb, sei->lpVerb);
1835 __SHCloneStrWtoA(&parameters, sei->lpParameters);
1837
1838 BOOL fDefault = StrIsNullOrEmpty(sei->lpVerb);
1839 CMINVOKECOMMANDINFOEX ici = { sizeof(ici) };
1840 ici.fMask = SeeFlagsToCmicFlags(sei->fMask) | CMIC_MASK_UNICODE;
1841 ici.nShow = sei->nShow;
1842 if (!fDefault)
1843 {
1844 ici.lpVerb = verb;
1845 ici.lpVerbW = sei->lpVerb;
1846 }
1847 ici.hwnd = sei->hwnd;
1848 ici.lpParameters = parameters;
1849 ici.lpParametersW = sei->lpParameters;
1850 ici.lpDirectory = dir;
1851 ici.lpDirectoryW = sei->lpDirectory;
1852 ici.dwHotKey = sei->dwHotKey;
1853 ici.hIcon = sei->hIcon;
1854 if (ici.fMask & (CMIC_MASK_HASLINKNAME | CMIC_MASK_HASTITLE))
1855 ici.lpTitleW = sei->lpClass;
1856
1857 enum { idFirst = 1, idLast = 0x7fff };
1858 HMENU hMenu = CreatePopupMenu();
1859 // Note: Windows does not pass CMF_EXTENDEDVERBS so "hidden" verbs cannot be executed
1860 hr = cm->QueryContextMenu(hMenu, 0, idFirst, idLast, fDefault ? CMF_DEFAULTONLY : 0);
1861 if (!FAILED_UNEXPECTEDLY(hr))
1862 {
1863 if (fDefault)
1864 {
1865 INT uDefault = GetMenuDefaultItem(hMenu, FALSE, 0);
1866 uDefault = (uDefault != -1) ? uDefault - idFirst : 0;
1867 ici.lpVerb = MAKEINTRESOURCEA(uDefault);
1868 ici.lpVerbW = MAKEINTRESOURCEW(uDefault);
1869 }
1870
1871 hr = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
1872 if (!FAILED_UNEXPECTEDLY(hr))
1873 hr = S_OK;
1874 }
1875
1876 DestroyMenu(hMenu);
1877
1878 return hr;
1879}
1880
1881
1882/*************************************************************************
1883 * ShellExecute_FromContextMenu [Internal]
1884 */
1886{
1887 HKEY hkey, hkeycm = 0;
1888 WCHAR szguid[39];
1889 HRESULT hr;
1890 GUID guid;
1891 DWORD i;
1892 LONG r;
1893
1894 TRACE("%s\n", debugstr_w(sei->lpFile));
1895
1896 hkey = ShellExecute_GetClassKey(sei);
1897 if (!hkey)
1898 return ERROR_FUNCTION_FAILED;
1899
1900 // FIXME: Words cannot describe how broken this is, all of it needs to die
1901 r = RegOpenKeyW(hkey, L"shellex\\ContextMenuHandlers", &hkeycm);
1902 if (r == ERROR_SUCCESS)
1903 {
1904 i = 0;
1905 while (1)
1906 {
1907 r = RegEnumKeyW(hkeycm, i++, szguid, ARRAY_SIZE(szguid));
1908 if (r != ERROR_SUCCESS)
1909 break;
1910
1911 hr = CLSIDFromString(szguid, &guid);
1912 if (SUCCEEDED(hr))
1913 {
1914 /* stop at the first one that succeeds in running */
1915 hr = shellex_load_object_and_run(hkey, &guid, sei);
1916 if (SUCCEEDED(hr))
1917 break;
1918 }
1919 }
1920 RegCloseKey(hkeycm);
1921 }
1922
1923 if (hkey != sei->hkeyClass)
1924 RegCloseKey(hkey);
1925 return r;
1926}
1927
1928static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc);
1929
1931{
1932 WCHAR execCmd[1024], classname[1024];
1933 /* launch a document by fileclass like 'WordPad.Document.1' */
1934 /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
1935 /* FIXME: wcmd should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */
1936 ULONG cmask = (psei->fMask & SEE_MASK_CLASSALL);
1937 DWORD resultLen;
1938 BOOL done;
1939 UINT_PTR rslt;
1940
1941 /* FIXME: remove following block when SHELL_quote_and_execute supports hkeyClass parameter */
1942 if (cmask != SEE_MASK_CLASSNAME)
1943 {
1944 WCHAR wcmd[1024];
1946 (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL,
1947 psei->lpVerb,
1948 execCmd, sizeof(execCmd));
1949
1950 /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
1951 TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
1952
1953 wcmd[0] = '\0';
1954 done = SHELL_ArgifyW(wcmd, ARRAY_SIZE(wcmd), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, psei->lpParameters,
1955 &resultLen, (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL);
1956 if (!done && wszApplicationName[0])
1957 {
1958#if 0 // Given HKCR\.test=SZ:"test" and HKCR\test\shell\open\command=SZ:"cmd.exe /K echo.Hello", no filename is
1959 // appended on Windows when there is no %1 nor %L when executed with: shlextdbg.exe /shellexec=c:\file.test /INVOKE
1960 strcatW(wcmd, L" ");
1961 if (*wszApplicationName != '"')
1962 {
1963 strcatW(wcmd, L"\"");
1964 strcatW(wcmd, wszApplicationName);
1965 strcatW(wcmd, L"\"");
1966 }
1967 else
1968 strcatW(wcmd, wszApplicationName);
1969#endif
1970 }
1971 if (resultLen > ARRAY_SIZE(wcmd))
1972 ERR("Argify buffer not large enough... truncating\n");
1973 return execfunc(wcmd, NULL, FALSE, psei, psei_out);
1974 }
1975
1976 strcpyW(classname, psei->lpClass);
1977 rslt = SHELL_FindExecutableByVerb(psei->lpVerb, NULL, classname, execCmd, sizeof(execCmd));
1978
1979 TRACE("SHELL_FindExecutableByVerb returned %u (%s, %s)\n", (unsigned int)rslt, debugstr_w(classname), debugstr_w(execCmd));
1980 if (33 > rslt)
1981 return rslt;
1982 rslt = SHELL_quote_and_execute( execCmd, L"", classname,
1983 wszApplicationName, NULL, psei,
1984 psei_out, execfunc );
1985 return rslt;
1986
1987}
1988
1989static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen)
1990{
1992 BOOL appKnownSingular = FALSE;
1993
1994 /* last chance to translate IDList: now also allow CLSID paths */
1996 if (buffer[0] == ':' && buffer[1] == ':') {
1997 /* open shell folder for the specified class GUID */
1998 if (strlenW(buffer) + 1 > parametersLen)
1999 ERR("parameters len exceeds buffer size (%i > %i), truncating\n",
2000 lstrlenW(buffer) + 1, parametersLen);
2001 lstrcpynW(wszParameters, buffer, parametersLen);
2002 if (strlenW(L"explorer.exe") > dwApplicationNameLen)
2003 ERR("application len exceeds buffer size (%i), truncating\n",
2004 dwApplicationNameLen);
2005 lstrcpynW(wszApplicationName, L"explorer.exe", dwApplicationNameLen);
2006 appKnownSingular = TRUE;
2007
2008 sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
2009 } else {
2011 DWORD attribs;
2012 DWORD resultLen;
2013 /* Check if we're executing a directory and if so use the
2014 handler for the Folder class */
2019 HCR_GetExecuteCommandW(0, L"Folder",
2020 sei->lpVerb,
2021 buffer, sizeof(buffer))) {
2022 SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
2023 buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen,
2024 !StrIsNullOrEmpty(sei->lpDirectory) ? sei->lpDirectory : NULL);
2025 if (resultLen > dwApplicationNameLen)
2026 ERR("Argify buffer not large enough... truncating\n"); // FIXME: Report this to the caller?
2027 appKnownSingular = FALSE;
2028 // HACKFIX: We really want the !appKnownSingular code in SHELL_execute to split the
2029 // parameters for us but we cannot guarantee that the exe in the registry is quoted.
2030 // We have now turned 'explorer.exe "%1" into 'explorer.exe "c:\path\from\pidl"' and
2031 // need to split to application and parameters.
2032 LPCWSTR params = PathGetArgsW(wszApplicationName);
2033 lstrcpynW(wszParameters, params, parametersLen);
2034 PathRemoveArgsW(wszApplicationName);
2035 PathUnquoteSpacesW(wszApplicationName);
2036 appKnownSingular = TRUE;
2037 }
2038 sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
2039 }
2040 }
2041 return appKnownSingular;
2042}
2043
2044static BOOL
2047 _In_ LPCITEMIDLIST pidl)
2048{
2049 // Bind pidl
2050 CComPtr<IShellFolder> psfFolder;
2051 LPCITEMIDLIST pidlLast;
2052 HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psfFolder), &pidlLast);
2054 return FALSE;
2055
2056 // Get the context menu to invoke a command
2058 hr = psfFolder->GetUIObjectOf(NULL, 1, &pidlLast, IID_NULL_PPV_ARG(IContextMenu, &pCM));
2060 return FALSE;
2061
2062 // Invoke a command
2063 CMINVOKECOMMANDINFO ici = { sizeof(ici) };
2064 ici.fMask = (sei->fMask & SEE_CMIC_COMMON_BASICFLAGS) & ~CMIC_MASK_UNICODE; // FIXME: Unicode?
2065 ici.nShow = sei->nShow;
2066 ici.hwnd = sei->hwnd;
2067 char szVerb[VERBKEY_CCHMAX];
2068 if (sei->lpVerb && sei->lpVerb[0])
2069 {
2070 WideCharToMultiByte(CP_ACP, 0, sei->lpVerb, -1, szVerb, _countof(szVerb), NULL, NULL);
2071 szVerb[_countof(szVerb) - 1] = ANSI_NULL; // Avoid buffer overrun
2072 ici.lpVerb = szVerb;
2073 }
2074 else // The default verb?
2075 {
2076 HMENU hMenu = CreatePopupMenu();
2077 const INT idCmdFirst = 1, idCmdLast = 0x7FFF;
2078 hr = pCM->QueryContextMenu(hMenu, 0, idCmdFirst, idCmdLast, CMF_DEFAULTONLY);
2080 {
2081 DestroyMenu(hMenu);
2082 return FALSE;
2083 }
2084
2085 INT nDefaultID = GetMenuDefaultItem(hMenu, FALSE, 0);
2086 DestroyMenu(hMenu);
2087 if (nDefaultID == -1)
2088 nDefaultID = idCmdFirst;
2089
2090 ici.lpVerb = MAKEINTRESOURCEA(nDefaultID - idCmdFirst);
2091 }
2092 hr = pCM->InvokeCommand(&ici);
2093
2094 return !FAILED_UNEXPECTEDLY(hr);
2095}
2096
2097static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
2098{
2100 DWORD len;
2102
2103 /* Length of quotes plus length of command plus NULL terminator */
2104 len = 2 + lstrlenW(wcmd) + 1;
2105 if (wszParameters[0])
2106 {
2107 /* Length of space plus length of parameters */
2108 len += 1 + lstrlenW(wszParameters);
2109 }
2110 wszQuotedCmd.Allocate(len);
2111 /* Must quote to handle case where cmd contains spaces,
2112 * else security hole if malicious user creates executable file "C:\\Program"
2113 */
2114 strcpyW(wszQuotedCmd, L"\"");
2115 strcatW(wszQuotedCmd, wcmd);
2116 strcatW(wszQuotedCmd, L"\"");
2117 if (wszParameters[0])
2118 {
2119 strcatW(wszQuotedCmd, L" ");
2120 strcatW(wszQuotedCmd, wszParameters);
2121 }
2122
2123 TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(wszKeyname));
2124
2125 if (*wszKeyname)
2126 retval = execute_from_key(wszKeyname, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
2127 else
2128 retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out);
2129
2130 return retval;
2131}
2132
2134{
2137 LPCWSTR lpstrRes;
2138 INT iSize;
2139 DWORD len;
2140
2141 lpstrRes = strchrW(lpFile, ':');
2142 if (lpstrRes)
2143 iSize = lpstrRes - lpFile;
2144 else
2145 iSize = strlenW(lpFile);
2146
2147 TRACE("Got URL: %s\n", debugstr_w(lpFile));
2148 /* Looking for ...<protocol>\shell<lpVerb>\command */
2149 len = iSize + lstrlenW(L"\\shell\\") + lstrlenW(L"\\command") + 1;
2150 if (psei->lpVerb && *psei->lpVerb)
2151 len += lstrlenW(psei->lpVerb);
2152 else
2153 len += lstrlenW(L"open"); // FIXME: Use HCR_GetExecuteCommandW or AssocAPI
2154 lpstrProtocol.Allocate(len);
2155 memcpy(lpstrProtocol, lpFile, iSize * sizeof(WCHAR));
2156 lpstrProtocol[iSize] = '\0';
2157 strcatW(lpstrProtocol, L"\\shell\\");
2158 strcatW(lpstrProtocol, psei->lpVerb && *psei->lpVerb ? psei->lpVerb : L"open");
2159 strcatW(lpstrProtocol, L"\\command");
2160
2161 retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters,
2162 wcmd, execfunc, psei, psei_out);
2163
2164 return retval;
2165}
2166
2168{
2169 WCHAR msg[2048];
2170 DWORD_PTR msgArguments[3] = { (DWORD_PTR)filename, 0, 0 };
2171 const DWORD error_code = GetLastError();
2172
2173 if (retval == SE_ERR_NOASSOC)
2175 else
2177 NULL,
2178 error_code,
2180 msg,
2181 ARRAY_SIZE(msg),
2182 (va_list*)msgArguments);
2183
2185 SetLastError(error_code); // Restore
2186}
2187
2189{
2191 DWORD len;
2192
2194 if (!len) return NULL;
2195
2196 if (!buf.Allocate(len))
2197 return NULL;
2198
2200 if (!len)
2201 return NULL;
2202
2203 return buf.Detach();
2204}
2205
2206/*************************************************************************
2207 * SHELL_execute [Internal]
2208 */
2210{
2211 static const DWORD unsupportedFlags =
2213
2214 DWORD len;
2216 BOOL appKnownSingular = FALSE;
2217
2218 /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */
2219 sei->hProcess = NULL;
2220 SHELLEXECUTEINFOW sei_tmp = *sei;
2221
2222 TRACE("mask=0x%08x hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n",
2223 sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb),
2224 debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters),
2225 debugstr_w(sei_tmp.lpDirectory), sei_tmp.nShow,
2226 ((sei_tmp.fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME) ?
2227 debugstr_w(sei_tmp.lpClass) : "not used");
2228
2229 // Call hooks before expanding and resolving strings
2231 if (hr != S_FALSE)
2232 {
2233 int err = Win32ErrFromHInst(sei->hInstApp);
2234 if (err <= 0)
2235 {
2236 sei->hInstApp = (HINSTANCE)UlongToHandle(42);
2237 return TRUE;
2238 }
2240 return FALSE;
2241 }
2242
2243 /* make copies of all path/command strings */
2244 CHeapPtr<WCHAR, CLocalAllocator> wszApplicationName;
2245 DWORD dwApplicationNameLen = MAX_PATH + 2;
2246 if (!sei_tmp.lpFile)
2247 {
2248 wszApplicationName.Allocate(dwApplicationNameLen);
2249 *wszApplicationName = '\0';
2250 }
2251 else if (*sei_tmp.lpFile == '\"' && sei_tmp.lpFile[(len = strlenW(sei_tmp.lpFile))-1] == '\"')
2252 {
2253 if(len-1 >= dwApplicationNameLen)
2254 dwApplicationNameLen = len;
2255
2256 wszApplicationName.Allocate(dwApplicationNameLen);
2257 memcpy(wszApplicationName, sei_tmp.lpFile + 1, len * sizeof(WCHAR));
2258
2259 if(len > 2)
2260 wszApplicationName[len-2] = '\0';
2261 appKnownSingular = TRUE;
2262
2263 TRACE("wszApplicationName=%s\n", debugstr_w(wszApplicationName));
2264 }
2265 else
2266 {
2267 DWORD l = strlenW(sei_tmp.lpFile) + 1;
2268 if(l > dwApplicationNameLen) dwApplicationNameLen = l + 1;
2269 wszApplicationName.Allocate(dwApplicationNameLen);
2270 memcpy(wszApplicationName, sei_tmp.lpFile, l * sizeof(WCHAR));
2271
2272 if (wszApplicationName[2] == 0 && wszApplicationName[1] == L':' &&
2273 ((L'A' <= wszApplicationName[0] && wszApplicationName[0] <= L'Z') ||
2274 (L'a' <= wszApplicationName[0] && wszApplicationName[0] <= L'z')))
2275 {
2276 // 'C:' --> 'C:\'
2277 PathAddBackslashW(wszApplicationName);
2278 }
2279 }
2280
2281 WCHAR parametersBuffer[1024];
2282 LPWSTR wszParameters = parametersBuffer;
2284 DWORD parametersLen = _countof(parametersBuffer);
2285
2286 if (sei_tmp.lpParameters)
2287 {
2288 len = lstrlenW(sei_tmp.lpParameters) + 1;
2289 if (len > parametersLen)
2290 {
2291 wszParamAlloc.Allocate(len);
2292 wszParameters = wszParamAlloc;
2293 parametersLen = len;
2294 }
2295 strcpyW(wszParameters, sei_tmp.lpParameters);
2296 }
2297 else
2298 *wszParameters = L'\0';
2299
2300 // Get the working directory
2301 WCHAR dirBuffer[MAX_PATH];
2302 LPWSTR wszDir = dirBuffer;
2303 wszDir[0] = UNICODE_NULL;
2305 if (sei_tmp.lpDirectory && *sei_tmp.lpDirectory)
2306 {
2307 if (sei_tmp.fMask & SEE_MASK_DOENVSUBST)
2308 {
2309 LPWSTR tmp = expand_environment(sei_tmp.lpDirectory);
2310 if (tmp)
2311 {
2312 wszDirAlloc.Attach(tmp);
2313 wszDir = wszDirAlloc;
2314 }
2315 }
2316 else
2317 {
2318 __SHCloneStrW(&wszDirAlloc, sei_tmp.lpDirectory);
2319 if (wszDirAlloc)
2320 wszDir = wszDirAlloc;
2321 }
2322 }
2323 if (!wszDir[0])
2324 {
2325 ::GetCurrentDirectoryW(_countof(dirBuffer), dirBuffer);
2326 wszDir = dirBuffer;
2327 }
2328 // NOTE: ShellExecute should accept the invalid working directory for historical reason.
2329 if (!PathIsDirectoryW(wszDir))
2330 {
2331 INT iDrive = PathGetDriveNumberW(wszDir);
2332 if (iDrive >= 0)
2333 {
2334 PathStripToRootW(wszDir);
2335 if (!PathIsDirectoryW(wszDir))
2336 {
2337 ::GetWindowsDirectoryW(dirBuffer, _countof(dirBuffer));
2338 wszDir = dirBuffer;
2339 }
2340 }
2341 }
2342
2343 /* adjust string pointers to point to the new buffers */
2344 sei_tmp.lpFile = wszApplicationName;
2345 sei_tmp.lpParameters = wszParameters;
2346 sei_tmp.lpDirectory = wszDir;
2347
2348 if (sei_tmp.fMask & unsupportedFlags)
2349 {
2350 FIXME("flags ignored: 0x%08x\n", sei_tmp.fMask & unsupportedFlags);
2351 }
2352
2353 /* process the IDList */
2354 if (sei_tmp.fMask & SEE_MASK_IDLIST &&
2356 {
2357 LPCITEMIDLIST pidl = (LPCITEMIDLIST)sei_tmp.lpIDList;
2358 hr = SHGetNameAndFlagsW(pidl, SHGDN_FORPARSING, wszApplicationName, dwApplicationNameLen, NULL);
2359 if (FAILED(hr))
2360 {
2361 if (dwApplicationNameLen)
2362 *wszApplicationName = UNICODE_NULL;
2363 if (!_ILIsDesktop(pidl))
2364 TRACE("Unable to get PIDL parsing path\n");
2365 }
2366 appKnownSingular = TRUE;
2367 TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName));
2368 }
2369
2370 if ((sei_tmp.fMask & SEE_MASK_DOENVSUBST) && !StrIsNullOrEmpty(sei_tmp.lpFile))
2371 {
2372 WCHAR *tmp = expand_environment(sei_tmp.lpFile);
2373 if (tmp)
2374 {
2375 wszApplicationName.Attach(tmp);
2376 sei_tmp.lpFile = wszApplicationName;
2377 }
2378 }
2379
2381 {
2382 hr = ShellExecute_ContextMenuVerb(&sei_tmp);
2383 if (SUCCEEDED(hr))
2384 {
2385 sei->hInstApp = (HINSTANCE)42;
2386 return TRUE;
2387 }
2388 }
2389
2391 {
2392 sei->hInstApp = (HINSTANCE) 33;
2393 return TRUE;
2394 }
2395
2396 if (sei_tmp.fMask & SEE_MASK_CLASSALL)
2397 {
2398 retval = SHELL_execute_class(wszApplicationName, &sei_tmp, sei, execfunc);
2399 if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
2400 {
2402
2403 //FIXME
2404 // need full path
2405
2406 Info.pcszFile = wszApplicationName;
2407 Info.pcszClass = NULL;
2408 Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
2409
2410 //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
2412 do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
2413 }
2414 return retval > 32;
2415 }
2416
2417 if (!(sei_tmp.fMask & SEE_MASK_IDLIST) && // Not an ID List
2418 (StrCmpNIW(sei_tmp.lpFile, L"shell:", 6) == 0 ||
2419 StrCmpNW(sei_tmp.lpFile, L"::{", 3) == 0))
2420 {
2421 CComHeapPtr<ITEMIDLIST> pidlParsed;
2422 hr = SHParseDisplayName(sei_tmp.lpFile, NULL, &pidlParsed, 0, NULL);
2423 if (SUCCEEDED(hr) && SHELL_InvokePidl(&sei_tmp, pidlParsed))
2424 {
2425 sei_tmp.hInstApp = (HINSTANCE)UlongToHandle(42);
2426 return TRUE;
2427 }
2428 }
2429
2430 /* Has the IDList not yet been translated? */
2431 if (sei_tmp.fMask & SEE_MASK_IDLIST)
2432 {
2433 appKnownSingular = SHELL_translate_idlist( &sei_tmp, wszParameters,
2434 parametersLen,
2435 wszApplicationName,
2436 dwApplicationNameLen );
2437 }
2438
2439 /* convert file URLs */
2440 if (UrlIsFileUrlW(sei_tmp.lpFile))
2441 {
2444 if (!buf.Allocate(size) || FAILED(PathCreateFromUrlW(sei_tmp.lpFile, buf, &size, 0)))
2445 {
2447 return FALSE;
2448 }
2449
2450 wszApplicationName.Attach(buf.Detach());
2451 sei_tmp.lpFile = wszApplicationName;
2452 }
2453
2454 /* Else, try to execute the filename */
2455 TRACE("execute: %s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir));
2456
2457 /* separate out command line arguments from executable file name */
2458 LPCWSTR lpFile = sei_tmp.lpFile;
2459 if (!*sei_tmp.lpParameters && !appKnownSingular)
2460 {
2461 /* If the executable path is quoted, handle the rest of the command line as parameters. */
2462 if (sei_tmp.lpFile[0] == L'"')
2463 {
2464 LPWSTR pszArgs = PathGetArgsW(wszApplicationName);
2465 PathRemoveArgsW(wszApplicationName);
2466 PathUnquoteSpacesW(wszApplicationName);
2467 parametersLen = lstrlenW(pszArgs);
2468 if (parametersLen < _countof(parametersBuffer))
2469 {
2470 StringCchCopyW(parametersBuffer, _countof(parametersBuffer), pszArgs);
2471 wszParameters = parametersBuffer;
2472 }
2473 else
2474 {
2475 wszParamAlloc.Attach(StrDupW(pszArgs));
2476 wszParameters = wszParamAlloc;
2477 }
2478 }
2479 /* We have to test sei instead of sei_tmp because sei_tmp had its
2480 * input fMask modified above in SHELL_translate_idlist.
2481 * This code is needed to handle the case where we only have an
2482 * lpIDList with multiple CLSID/PIDL's (not 'My Computer' only) */
2483 else if ((sei->fMask & SEE_MASK_IDLIST) == SEE_MASK_IDLIST)
2484 {
2485 WCHAR buffer[MAX_PATH], xlpFile[MAX_PATH];
2486 LPWSTR space, s;
2487
2488 LPWSTR beg = wszApplicationName;
2489 for(s = beg; (space = const_cast<LPWSTR>(strchrW(s, L' '))); s = space + 1)
2490 {
2491 int idx = space - sei_tmp.lpFile;
2492 memcpy(buffer, sei_tmp.lpFile, idx * sizeof(WCHAR));
2493 buffer[idx] = '\0';
2494
2495 if (SearchPathW(*sei_tmp.lpDirectory ? sei_tmp.lpDirectory : NULL,
2496 buffer, L".exe", _countof(xlpFile), xlpFile, NULL))
2497 {
2498 /* separate out command from parameter string */
2499 LPCWSTR p = space + 1;
2500
2501 while(isspaceW(*p))
2502 ++p;
2503
2504 strcpyW(wszParameters, p);
2505 *space = L'\0';
2506
2507 break;
2508 }
2509 }
2510 }
2511 }
2512
2513 WCHAR wcmdBuffer[1024];
2514 LPWSTR wcmd = wcmdBuffer;
2515 DWORD wcmdLen = _countof(wcmdBuffer);
2517
2518 /* Only execute if it has an executable extension */
2519 if (PathIsExeW(lpFile))
2520 {
2521 len = lstrlenW(wszApplicationName) + 3;
2522 if (sei_tmp.lpParameters[0])
2523 len += 1 + lstrlenW(wszParameters);
2524 if (len > wcmdLen)
2525 {
2526 wcmdAlloc.Allocate(len);
2527 wcmd = wcmdAlloc;
2528 wcmdLen = len;
2529 }
2530 swprintf(wcmd, L"\"%s\"", (LPWSTR)wszApplicationName);
2531 if (sei_tmp.lpParameters[0])
2532 {
2533 strcatW(wcmd, L" ");
2534 strcatW(wcmd, wszParameters);
2535 }
2536
2537 retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei);
2538 if (retval > 32)
2539 return TRUE;
2540 }
2541
2542 /* Else, try to find the executable */
2543 WCHAR wszKeyname[256];
2545 wcmd[0] = UNICODE_NULL;
2546 retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, wszKeyname, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
2547 if (retval > 32) /* Found */
2548 {
2549 retval = SHELL_quote_and_execute(wcmd, wszParameters, wszKeyname,
2550 wszApplicationName, env, &sei_tmp,
2551 sei, execfunc);
2552 }
2553 else if (PathIsDirectoryW(lpFile))
2554 {
2555 WCHAR wExec[MAX_PATH];
2557 if (lpQuotedFile.Allocate(strlenW(lpFile) + 3))
2558 {
2559 retval = SHELL_FindExecutable(sei_tmp.lpDirectory, L"explorer",
2560 L"open", wExec, MAX_PATH,
2561 NULL, &env, NULL, NULL);
2562 if (retval > 32)
2563 {
2564 swprintf(lpQuotedFile, L"\"%s\"", lpFile);
2565 retval = SHELL_quote_and_execute(wExec, lpQuotedFile,
2566 wszKeyname,
2567 wszApplicationName, env,
2568 &sei_tmp, sei, execfunc);
2569 }
2570 }
2571 else
2572 retval = 0; /* Out of memory */
2573 }
2574 else if (PathIsURLW(lpFile)) /* File not found, check for URL */
2575 {
2576 retval = SHELL_execute_url(lpFile, wcmd, &sei_tmp, sei, execfunc );
2577 }
2578 /* Check if file specified is in the form www.??????.*** */
2579 else if (!strncmpiW(lpFile, L"www", 3))
2580 {
2581 /* if so, prefix lpFile with http:// and call ShellExecute */
2582 WCHAR lpstrTmpFile[256];
2583 strcpyW(lpstrTmpFile, L"http://");
2584 strcatW(lpstrTmpFile, lpFile); // FIXME: Possible buffer overflow
2585 // FIXME: This will not correctly return the hProcess to the caller
2586 retval = (UINT_PTR)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0);
2587 }
2588
2589 TRACE("retval %lu\n", retval);
2590
2591 if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
2592 {
2593 if (retval == SE_ERR_NOASSOC && !(sei->fMask & SEE_MASK_CLASSALL))
2594 retval = InvokeOpenWith(sei_tmp.hwnd, *sei);
2595 if (retval <= 32)
2596 do_error_dialog(retval, sei_tmp.hwnd, lpFile);
2597 }
2598
2599 sei->hInstApp = (HINSTANCE)(retval > 32 ? 33 : retval);
2600
2601 return retval > 32;
2602}
2603
2604/*************************************************************************
2605 * ShellExecuteA [SHELL32.290]
2606 */
2608 LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
2609{
2611
2612 TRACE("%p,%s,%s,%s,%s,%d\n",
2613 hWnd, debugstr_a(lpVerb), debugstr_a(lpFile),
2614 debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd);
2615
2616 sei.cbSize = sizeof(sei);
2618 sei.hwnd = hWnd;
2619 sei.lpVerb = lpVerb;
2620 sei.lpFile = lpFile;
2621 sei.lpParameters = lpParameters;
2623 sei.nShow = iShowCmd;
2624 sei.lpIDList = 0;
2625 sei.lpClass = 0;
2626 sei.hkeyClass = 0;
2627 sei.dwHotKey = 0;
2628 sei.hProcess = 0;
2629
2631 sei.fMask |= SEE_MASK_NOASYNC;
2632 ShellExecuteExA(&sei);
2633 return sei.hInstApp;
2634}
2635
2636static DWORD
2638{
2639 // FIXME
2640 if (SHELL_execute(sei, SHELL_ExecuteW))
2641 return ERROR_SUCCESS;
2643#if DBG
2644 if (!err)
2645 DbgPrint("FIXME: Failed with error 0 on '%ls'\n", sei->lpFile);
2646#endif
2647 return err ? err : ERROR_FILE_NOT_FOUND;
2648}
2649
2650static VOID
2652 _In_ const SHELLEXECUTEINFOW *ExecInfo,
2653 _In_opt_ LPCWSTR pszCaption,
2654 _In_ DWORD dwError)
2655{
2656 // FIXME: Show error message
2657}
2658
2659/*************************************************************************
2660 * ShellExecuteExA [SHELL32.292]
2661 */
2662BOOL
2663WINAPI
2666{
2667 SHELLEXECUTEINFOW seiW;
2668 BOOL ret;
2669 WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL, *wClass = NULL;
2670
2671 TRACE("%p\n", sei);
2672
2673 if (sei->cbSize != sizeof(SHELLEXECUTEINFOA))
2674 {
2677 return FALSE;
2678 }
2679
2680 memcpy(&seiW, sei, sizeof(SHELLEXECUTEINFOW));
2681
2682 seiW.cbSize = sizeof(SHELLEXECUTEINFOW);
2683
2684 if (sei->lpVerb)
2685 seiW.lpVerb = __SHCloneStrAtoW(&wVerb, sei->lpVerb);
2686
2687 if (sei->lpFile)
2688 seiW.lpFile = __SHCloneStrAtoW(&wFile, sei->lpFile);
2689
2690 if (sei->lpParameters)
2691 seiW.lpParameters = __SHCloneStrAtoW(&wParameters, sei->lpParameters);
2692
2693 if (sei->lpDirectory)
2694 seiW.lpDirectory = __SHCloneStrAtoW(&wDirectory, sei->lpDirectory);
2695
2696 if ((sei->fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME && sei->lpClass)
2697 seiW.lpClass = __SHCloneStrAtoW(&wClass, sei->lpClass);
2698 else
2699 seiW.lpClass = NULL;
2700
2701 ret = ShellExecuteExW(&seiW);
2702
2703 sei->hInstApp = seiW.hInstApp;
2704
2705 if (sei->fMask & SEE_MASK_NOCLOSEPROCESS)
2706 sei->hProcess = seiW.hProcess;
2707
2708 SHFree(wVerb);
2709 SHFree(wFile);
2710 SHFree(wParameters);
2711 SHFree(wDirectory);
2712 SHFree(wClass);
2713
2714 return ret;
2715}
2716
2717/*************************************************************************
2718 * ShellExecuteExW [SHELL32.293]
2719 */
2720BOOL
2721WINAPI
2724{
2725 HRESULT hrCoInit;
2726 DWORD dwError;
2727 ULONG fOldMask;
2728
2729 if (sei->cbSize != sizeof(SHELLEXECUTEINFOW))
2730 {
2733 return FALSE;
2734 }
2735
2736 hrCoInit = SHCoInitializeAnyApartment();
2737
2738 if (SHRegGetBoolUSValueW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
2739 L"MaximizeApps", FALSE, FALSE))
2740 {
2741 switch (sei->nShow)
2742 {
2743 case SW_SHOW:
2744 case SW_SHOWDEFAULT:
2745 case SW_SHOWNORMAL:
2746 case SW_RESTORE:
2747 sei->nShow = SW_SHOWMAXIMIZED;
2748 break;
2749 default:
2750 break;
2751 }
2752 }
2753
2754 fOldMask = sei->fMask;
2755
2756 if (!(fOldMask & SEE_MASK_NOASYNC) && SHELL_InRunDllProcess())
2758
2759 dwError = ShellExecute_Normal(sei);
2760
2761 if (dwError && dwError != ERROR_DLL_NOT_FOUND && dwError != ERROR_CANCELLED)
2762 ShellExecute_ShowError(sei, NULL, dwError);
2763
2764 sei->fMask = fOldMask;
2765
2766 if (SUCCEEDED(hrCoInit))
2768
2769 if (dwError)
2770 SetLastError(dwError);
2771
2772 return dwError == ERROR_SUCCESS;
2773}
2774
2775/*************************************************************************
2776 * ShellExecuteW [SHELL32.294]
2777 */
2779 LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
2780{
2782
2783 TRACE("\n");
2784 sei.cbSize = sizeof(sei);
2786 sei.hwnd = hwnd;
2787 sei.lpVerb = lpVerb;
2788 sei.lpFile = lpFile;
2789 sei.lpParameters = lpParameters;
2791 sei.nShow = nShowCmd;
2792 sei.lpIDList = 0;
2793 sei.lpClass = 0;
2794 sei.hkeyClass = 0;
2795 sei.dwHotKey = 0;
2796 sei.hProcess = 0;
2797
2799 sei.fMask |= SEE_MASK_NOASYNC;
2800 ShellExecuteExW(&sei);
2801 return sei.hInstApp;
2802}
2803
2804/*************************************************************************
2805 * WOWShellExecute [SHELL32.@]
2806 *
2807 * FIXME: the callback function most likely doesn't work the same way on Windows.
2808 */
2810 LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback)
2811{
2812 SHELLEXECUTEINFOW seiW;
2813 WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL;
2814 HANDLE hProcess = 0;
2815
2816 seiW.lpVerb = lpVerb ? __SHCloneStrAtoW(&wVerb, lpVerb) : NULL;
2817 seiW.lpFile = lpFile ? __SHCloneStrAtoW(&wFile, lpFile) : NULL;
2818 seiW.lpParameters = lpParameters ? __SHCloneStrAtoW(&wParameters, lpParameters) : NULL;
2819 seiW.lpDirectory = lpDirectory ? __SHCloneStrAtoW(&wDirectory, lpDirectory) : NULL;
2820
2821 seiW.cbSize = sizeof(seiW);
2822 seiW.fMask = 0;
2823 seiW.hwnd = hWnd;
2824 seiW.nShow = iShowCmd;
2825 seiW.lpIDList = 0;
2826 seiW.lpClass = 0;
2827 seiW.hkeyClass = 0;
2828 seiW.dwHotKey = 0;
2829 seiW.hProcess = hProcess;
2830
2832
2833 SHFree(wVerb);
2834 SHFree(wFile);
2835 SHFree(wParameters);
2836 SHFree(wDirectory);
2837 return seiW.hInstApp;
2838}
2839
2840/*************************************************************************
2841 * OpenAs_RunDLLW [SHELL32.@]
2842 */
2843EXTERN_C void WINAPI
2845{
2847 TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow);
2849}
2850
2851/*************************************************************************
2852 * OpenAs_RunDLLA [SHELL32.@]
2853 */
2854EXTERN_C void WINAPI
2856{
2857 LPWSTR pszCmdLineW = NULL;
2858 TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow);
2859
2860 if (cmdline)
2861 __SHCloneStrAtoW(&pszCmdLineW, cmdline);
2862 OpenAs_RunDLLW(hwnd, hinst, pszCmdLineW, cmdshow);
2863 SHFree(pszCmdLineW);
2864}
2865
2866/*************************************************************************/
2867
2868static LPCWSTR
2869SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0)
2870{
2871 LPCWSTR pch;
2872 size_t ich = 0;
2873 if (*psz == L'"')
2874 {
2875 // 1st argument is quoted. the string in quotes is quoted 1st argument.
2876 // [pch] --> [pszArg0+ich]
2877 for (pch = psz + 1; *pch && ich + 1 < cchArg0; ++ich, ++pch)
2878 {
2879 if (*pch == L'"' && pch[1] == L'"')
2880 {
2881 // doubled double quotations found!
2882 pszArg0[ich] = L'"';
2883 }
2884 else if (*pch == L'"')
2885 {
2886 // single double quotation found!
2887 ++pch;
2888 break;
2889 }
2890 else
2891 {
2892 // otherwise
2893 pszArg0[ich] = *pch;
2894 }
2895 }
2896 }
2897 else
2898 {
2899 // 1st argument is unquoted. non-space sequence is 1st argument.
2900 // [pch] --> [pszArg0+ich]
2901 for (pch = psz; *pch && !iswspace(*pch) && ich + 1 < cchArg0; ++ich, ++pch)
2902 {
2903 pszArg0[ich] = *pch;
2904 }
2905 }
2906 pszArg0[ich] = 0;
2907
2908 // skip space
2909 while (iswspace(*pch))
2910 ++pch;
2911
2912 return pch;
2913}
2914
2916 HWND hwnd,
2917 LPCWSTR pwszCommand,
2918 LPCWSTR pwszStartDir,
2919 int nShow,
2920 LPVOID pUnused,
2921 DWORD dwSeclFlags)
2922{
2925 LPCWSTR pszVerb = NULL;
2926 WCHAR szFile[MAX_PATH], szFile2[MAX_PATH];
2927 HRESULT hr;
2928 LPCWSTR pchParams;
2929 LPWSTR lpCommand = NULL;
2930
2931 if (pwszCommand == NULL)
2933 1, (ULONG_PTR*)pwszCommand);
2934
2935 __SHCloneStrW(&lpCommand, pwszCommand);
2936 StrTrimW(lpCommand, L" \t");
2937
2938 if (dwSeclFlags & SECL_NO_UI)
2940 if (dwSeclFlags & SECL_LOG_USAGE)
2942 if (dwSeclFlags & SECL_USE_IDLIST)
2944
2945 if (dwSeclFlags & SECL_RUNAS)
2946 {
2947 dwSize = 0;
2948 hr = AssocQueryStringW(ASSOCF_NONE, ASSOCSTR_COMMAND, lpCommand, L"runas", NULL, &dwSize);
2949 if (SUCCEEDED(hr) && dwSize != 0)
2950 {
2951 pszVerb = L"runas";
2952 }
2953 }
2954
2955 if (PathIsURLW(lpCommand) || UrlIsW(lpCommand, URLIS_APPLIABLE))
2956 {
2957 StringCchCopyW(szFile, _countof(szFile), lpCommand);
2958 pchParams = NULL;
2959 }
2960 else
2961 {
2962 PCWSTR apPathList[2];
2963
2964 pchParams = SplitParams(lpCommand, szFile, _countof(szFile));
2965 if (szFile[0] != UNICODE_NULL && szFile[1] == L':' &&
2966 szFile[2] == UNICODE_NULL)
2967 {
2968 PathAddBackslashW(szFile);
2969 }
2970
2971 WCHAR szCurDir[MAX_PATH];
2972 GetCurrentDirectoryW(_countof(szCurDir), szCurDir);
2973 if (pwszStartDir)
2974 {
2975 SetCurrentDirectoryW(pwszStartDir);
2976 }
2977
2978 if ((PathIsRelativeW(szFile) &&
2979 GetFullPathNameW(szFile, _countof(szFile2), szFile2, NULL) &&
2980 PathFileExistsW(szFile2)) ||
2981 SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL))
2982 {
2983 StringCchCopyW(szFile, _countof(szFile), szFile2);
2984 }
2985
2986 apPathList[0] = pwszStartDir;
2987 apPathList[1] = NULL;
2988 PathFindOnPathExW(szFile, apPathList, WHICH_DEFAULT);
2989
2990 if (!(dwSeclFlags & SECL_ALLOW_NONEXE))
2991 {
2992 if (!GetBinaryTypeW(szFile, &dwType))
2993 {
2994 SHFree(lpCommand);
2995
2996 if (!(dwSeclFlags & SECL_NO_UI))
2997 {
2998 WCHAR szText[128 + MAX_PATH], szFormat[128];
3000 StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
3001 MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
3002 }
3003 return CO_E_APPNOTFOUND;
3004 }
3005 }
3006 else
3007 {
3009 {
3010 SHFree(lpCommand);
3011
3012 if (!(dwSeclFlags & SECL_NO_UI))
3013 {
3014 WCHAR szText[128 + MAX_PATH], szFormat[128];
3016 StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
3017 MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
3018 }
3020 }
3021 }
3022 }
3023
3024 ZeroMemory(&info, sizeof(info));
3025 info.cbSize = sizeof(info);
3026 info.fMask = dwFlags;
3027 info.hwnd = hwnd;
3028 info.lpVerb = pszVerb;
3029 info.lpFile = szFile;
3030 info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL;
3031 info.lpDirectory = pwszStartDir;
3032 info.nShow = nShow;
3034 SHFree(lpCommand);
3035 return HRESULT_FROM_WIN32(error);
3036}
3037
3038/*************************************************************************
3039 * RealShellExecuteExA (SHELL32.266)
3040 */
3045 _In_opt_ LPCSTR lpOperation,
3046 _In_opt_ LPCSTR lpFile,
3047 _In_opt_ LPCSTR lpParameters,
3049 _In_opt_ LPSTR lpReturn,
3052 _In_ INT nCmdShow,
3053 _Out_opt_ PHANDLE lphProcess,
3055{
3056 SHELLEXECUTEINFOA ExecInfo;
3057
3058 TRACE("(%p, %s, %s, %s, %s, %p, %s, %p, %u, %p, %lu)\n",
3059 hwnd, debugstr_a(lpOperation), debugstr_a(lpFile), debugstr_a(lpParameters),
3061 lpReserved, nCmdShow, lphProcess, dwFlags);
3062
3063 ZeroMemory(&ExecInfo, sizeof(ExecInfo));
3064 ExecInfo.cbSize = sizeof(ExecInfo);
3066 ExecInfo.hwnd = hwnd;
3067 ExecInfo.lpVerb = lpOperation;
3068 ExecInfo.lpFile = lpFile;
3069 ExecInfo.lpParameters = lpParameters;
3070 ExecInfo.lpDirectory = lpDirectory;
3071 ExecInfo.nShow = (WORD)nCmdShow;
3072
3073 if (lpReserved)
3074 {
3075 ExecInfo.fMask |= SEE_MASK_USE_RESERVED;
3076 ExecInfo.hInstApp = (HINSTANCE)lpReserved;
3077 }
3078
3079 if (lpTitle)
3080 {
3081 ExecInfo.fMask |= SEE_MASK_HASTITLE;
3082 ExecInfo.lpClass = lpTitle;
3083 }
3084
3085 if (dwFlags & 1)
3086 ExecInfo.fMask |= SEE_MASK_FLAG_SEPVDM;
3087
3088 if (dwFlags & 2)
3089 ExecInfo.fMask |= SEE_MASK_NO_CONSOLE;
3090
3091 if (lphProcess == NULL)
3092 {
3093 ShellExecuteExA(&ExecInfo);
3094 }
3095 else
3096 {
3097 ExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS;
3098 ShellExecuteExA(&ExecInfo);
3099 *lphProcess = ExecInfo.hProcess;
3100 }
3101
3102 return ExecInfo.hInstApp;
3103}
3104
3105/*************************************************************************
3106 * RealShellExecuteExW (SHELL32.267)
3107 */
3112 _In_opt_ LPCWSTR lpOperation,
3113 _In_opt_ LPCWSTR lpFile,
3114 _In_opt_ LPCWSTR lpParameters,
3116 _In_opt_ LPWSTR lpReturn,
3119 _In_ INT nCmdShow,
3120 _Out_opt_ PHANDLE lphProcess,
3122{
3123 SHELLEXECUTEINFOW ExecInfo;
3124
3125 TRACE("(%p, %s, %s, %s, %s, %p, %s, %p, %u, %p, %lu)\n",
3126 hwnd, debugstr_w(lpOperation), debugstr_w(lpFile), debugstr_w(lpParameters),
3128 lpReserved, nCmdShow, lphProcess, dwFlags);
3129
3130 ZeroMemory(&ExecInfo, sizeof(ExecInfo));
3131 ExecInfo.cbSize = sizeof(ExecInfo);
3133 ExecInfo.hwnd = hwnd;
3134 ExecInfo.lpVerb = lpOperation;
3135 ExecInfo.lpFile = lpFile;
3136 ExecInfo.lpParameters = lpParameters;
3137 ExecInfo.lpDirectory = lpDirectory;
3138 ExecInfo.nShow = (WORD)nCmdShow;
3139
3140 if (lpReserved)
3141 {
3142 ExecInfo.fMask |= SEE_MASK_USE_RESERVED;
3143 ExecInfo.hInstApp = (HINSTANCE)lpReserved;
3144 }
3145
3146 if (lpTitle)
3147 {
3148 ExecInfo.fMask |= SEE_MASK_HASTITLE;
3149 ExecInfo.lpClass = lpTitle;
3150 }
3151
3152 if (dwFlags & 1)
3153 ExecInfo.fMask |= SEE_MASK_FLAG_SEPVDM;
3154
3155 if (dwFlags & 2)
3156 ExecInfo.fMask |= SEE_MASK_NO_CONSOLE;
3157
3158 if (lphProcess == NULL)
3159 {
3160 ShellExecuteExW(&ExecInfo);
3161 }
3162 else
3163 {
3164 ExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS;
3165 ShellExecuteExW(&ExecInfo);
3166 *lphProcess = ExecInfo.hProcess;
3167 }
3168
3169 return ExecInfo.hInstApp;
3170}
3171
3172/*************************************************************************
3173 * RealShellExecuteA (SHELL32.265)
3174 */
3179 _In_opt_ LPCSTR lpOperation,
3180 _In_opt_ LPCSTR lpFile,
3181 _In_opt_ LPCSTR lpParameters,
3183 _In_opt_ LPSTR lpReturn,
3186 _In_ INT nCmdShow,
3187 _Out_opt_ PHANDLE lphProcess)
3188{
3190 lpOperation,
3191 lpFile,
3192 lpParameters,
3194 lpReturn,
3195 lpTitle,
3196 lpReserved,
3197 nCmdShow,
3198 lphProcess,
3199 0);
3200}
3201
3202/*************************************************************************
3203 * RealShellExecuteW (SHELL32.268)
3204 */
3209 _In_opt_ LPCWSTR lpOperation,
3210 _In_opt_ LPCWSTR lpFile,
3211 _In_opt_ LPCWSTR lpParameters,
3213 _In_opt_ LPWSTR lpReturn,
3216 _In_ INT nCmdShow,
3217 _Out_opt_ PHANDLE lphProcess)
3218{
3220 lpOperation,
3221 lpFile,
3222 lpParameters,
3224 lpReturn,
3225 lpTitle,
3226 lpReserved,
3227 nCmdShow,
3228 lphProcess,
3229 0);
3230}
3231
3232/*************************************************************************
3233 * PathProcessCommandW [Internal]
3234 *
3235 * @see https://learn.microsoft.com/en-us/windows/win32/api/shlobj/nf-shlobj-pathprocesscommand
3236 * @see ./wine/shellpath.c
3237 */
3240 _In_ PCWSTR pszSrc,
3241 _Out_writes_opt_(dwBuffSize) PWSTR pszDest,
3244{
3245 TRACE("%s, %p, %d, 0x%X\n", wine_dbgstr_w(pszSrc), pszDest, cchDest, dwFlags);
3246
3247 if (!pszSrc)
3248 return -1;
3249
3251 PCWSTR pchArg = NULL;
3252
3253 if (*pszSrc == L'"') // Quoted?
3254 {
3255 ++pszSrc;
3256
3257 PCWSTR pch = wcschr(pszSrc, L'"');
3258 if (pch)
3259 {
3260 szPath.SetString(pszSrc, pch - pszSrc);
3261 pchArg = pch + 1;
3262 }
3263 else
3264 {
3265 szPath = pszSrc;
3266 }
3267
3269 {
3271 szPath.ReleaseBuffer();
3272 if (!ret)
3273 return -1;
3274 }
3275 }
3276 else // Not quoted?
3277 {
3278 BOOL resolved = FALSE;
3279 BOOL resolveRelative = PathIsRelativeW(pszSrc) || (dwFlags & PPCF_FORCEQUALIFY);
3280 INT cchPath = 0;
3281
3282 for (INT ich = 0; ; ++ich)
3283 {
3284 szPath += pszSrc[ich];
3285
3286 if (pszSrc[ich] && pszSrc[ich] != L' ')
3287 continue;
3288
3289 szPath = szPath.Left(ich);
3290
3291 if (resolveRelative &&
3293 {
3294 szPath.ReleaseBuffer();
3295 szPath += pszSrc[ich];
3296 }
3297 else
3298 {
3299 szPath.ReleaseBuffer();
3300
3302 if (attrs != INVALID_FILE_ATTRIBUTES &&
3304 {
3305 resolved = TRUE;
3306 pchArg = pszSrc + ich;
3307
3309 break;
3310
3311 cchPath = ich;
3312 break;
3313 }
3314 else if (!resolveRelative)
3315 {
3316 szPath += pszSrc[ich];
3317 }
3318 }
3319
3320 if (!szPath[ich])
3321 {
3322 szPath.ReleaseBuffer(); // Remove excessive '\0'
3323 break;
3324 }
3325 }
3326
3327 if (!resolved)
3328 return -1;
3329
3330 if (cchPath && (dwFlags & PPCF_LONGESTPOSSIBLE))
3331 {
3332 szPath = szPath.Left(cchPath);
3333 pchArg = pszSrc + cchPath;
3334 }
3335 }
3336
3337 BOOL needsQuoting = (dwFlags & PPCF_ADDQUOTES) && wcschr(szPath, L' ');
3338 CStringW result = needsQuoting ? (L"\"" + szPath + L"\"") : szPath;
3339
3340 if (pchArg && (dwFlags & PPCF_ADDARGUMENTS))
3341 result += pchArg;
3342
3343 LONG requiredSize = result.GetLength() + 1;
3344 if (!pszDest)
3345 return requiredSize;
3346
3347 if (requiredSize > cchDest || StringCchCopyW(pszDest, cchDest, result) != S_OK)
3348 return -1;
3349
3350 return requiredSize;
3351}
3352
3353// The common helper of ShellExec_RunDLLA and ShellExec_RunDLLW
3354static VOID
3358 _In_ PCWSTR pszCmdLine,
3359 _In_ INT nCmdShow)
3360{
3361 TRACE("(%p, %p, %s, 0x%X)\n", hwnd, hInstance, wine_dbgstr_w(pszCmdLine), nCmdShow);
3362
3363 if (!pszCmdLine || !*pszCmdLine)
3364 return;
3365
3366 // '?' enables us to specify the additional mask value
3367 ULONG fNewMask = SEE_MASK_NOASYNC;
3368 if (*pszCmdLine == L'?') // 1st question
3369 {
3370 INT MaskValue;
3371 if (StrToIntExW(pszCmdLine + 1, STIF_SUPPORT_HEX, &MaskValue))
3372 fNewMask |= MaskValue;
3373
3374 PCWSTR pch2ndQuestion = StrChrW(pszCmdLine + 1, L'?'); // 2nd question
3375 if (pch2ndQuestion)
3376 pszCmdLine = pch2ndQuestion + 1;
3377 }
3378
3379 WCHAR szPath[2 * MAX_PATH];
3381 if (PathProcessCommandW(pszCmdLine, szPath, _countof(szPath), dwFlags) == -1)
3382 StrCpyNW(szPath, pszCmdLine, _countof(szPath));
3383
3384 // Split arguments from the path
3386 if (*Args)
3387 *(Args - 1) = UNICODE_NULL;
3388
3390
3391 // Execute
3392 SHELLEXECUTEINFOW execInfo = { sizeof(execInfo) };
3393 execInfo.fMask = fNewMask;
3394 execInfo.hwnd = hwnd;
3395 execInfo.lpFile = szPath;
3396 execInfo.lpParameters = Args;
3397 execInfo.nShow = nCmdShow;
3398 if (!ShellExecuteExW(&execInfo))
3399 {
3400 DWORD dwError = GetLastError();
3401 if (SHELL_InRunDllProcess()) // Is it a RUNDLL process?
3402 ExitProcess(dwError); // Terminate it now
3403 }
3404}
3405
3406/*************************************************************************
3407 * ShellExec_RunDLLA [SHELL32.358]
3408 *
3409 * @see https://www.hexacorn.com/blog/2024/11/30/1-little-known-secret-of-shellexec_rundll/
3410 */
3416 _In_ PCSTR pszCmdLine,
3417 _In_ INT nCmdShow)
3418{
3419 CStringW strCmdLine = pszCmdLine; // Keep
3420 ShellExec_RunDLL_Helper(hwnd, hInstance, strCmdLine, nCmdShow);
3421}
3422
3423/*************************************************************************
3424 * ShellExec_RunDLLW [SHELL32.359]
3425 *
3426 * @see https://www.hexacorn.com/blog/2024/11/30/1-little-known-secret-of-shellexec_rundll/
3427 */
3433 _In_ PCWSTR pszCmdLine,
3434 _In_ INT nCmdShow)
3435{
3436 ShellExec_RunDLL_Helper(hwnd, hInstance, pszCmdLine, nCmdShow);
3437}
BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
Definition: CBandSite.h:24
HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
HRESULT WINAPI SHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo)
HRESULT SH32_InvokeOpenWith(_In_ PCWSTR pszPath, _In_ LPCMINVOKECOMMANDINFO pici, _Out_ HANDLE *phProcess)
#define PRF_VERIFYEXISTS
Definition: PathResolve.cpp:38
#define PRF_TRYPROGRAMEXTENSIONS
Definition: PathResolve.cpp:40
#define PRF_FIRSTDIRDEF
Definition: PathResolve.cpp:41
#define SECL_USE_IDLIST
#define SECL_LOG_USAGE
#define shell32_hInstance
#define SECL_ALLOW_NONEXE
#define SECL_RUNAS
#define ShellExecCmdLine
#define SECL_NO_UI
#define DECLSPEC_HOTPATCH
Definition: _mingw.h:240
char ** Args
Definition: acdebug.h:353
char * va_list
Definition: acmsvcex.h:78
static int used
Definition: adh-main.c:39
static void startup(void)
unsigned int dir
Definition: maze.c:112
#define msg(x)
Definition: auth_time.c:54
HWND hWnd
Definition: settings.c:17
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:20
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define UlongToHandle(ul)
Definition: basetsd.h:91
#define EXTERN_C
Definition: basetyps.h:12
#define RegCloseKey(hKey)
Definition: registry.h:49
r l[0]
Definition: byte_order.h:168
HINSTANCE hInstance
Definition: charmap.c:19
Definition: bufpool.h:45
T * Detach()
Definition: atlalloc.h:168
bool Allocate(_In_ size_t nElements=1)
Definition: atlalloc.h:143
void Attach(T *lp)
Definition: atlalloc.h:162
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
wcscat
wcscpy
TCHAR lpTitle[80]
Definition: ctm.c:69
static LPCWSTR LPCWSTR LPCWSTR env
Definition: db.cpp:171
HDDEDATA WINAPI DdeClientTransaction(LPBYTE, DWORD, HCONV, HSZ, UINT, UINT, DWORD, LPDWORD)
Definition: ddeclient.c:1122
#define DMLERR_NO_ERROR
Definition: ddeml.h:242
BOOL WINAPI DdeUninitialize(DWORD)
Definition: ddemisc.c:1112
UINT WINAPI DdeInitializeW(LPDWORD, PFNCALLBACK, DWORD, DWORD)
Definition: ddemisc.c:1095
HCONV WINAPI DdeConnect(DWORD, HSZ, HSZ, PCONVCONTEXT)
Definition: ddeclient.c:84
UINT WINAPI DdeGetLastError(DWORD)
Definition: ddemisc.c:253
HSZ WINAPI DdeCreateStringHandleW(DWORD, LPCWSTR, INT)
Definition: ddemisc.c:608
BOOL WINAPI DdeDisconnect(HCONV)
Definition: ddeclient.c:1363
#define XTYP_EXECUTE
Definition: ddeml.h:185
#define CP_WINUNICODE
Definition: ddeml.h:33
BOOL WINAPI DdeFreeDataHandle(HDDEDATA)
Definition: ddemisc.c:1461
#define APPCMD_CLIENTONLY
Definition: ddeml.h:122
UINT WINAPI DdeInitializeA(LPDWORD, PFNCALLBACK, DWORD, DWORD)
Definition: ddemisc.c:1075
#define E_FAIL
Definition: ddrawi.h:102
static PVOID Env
Definition: dem.c:259
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned int idx
Definition: utils.c:41
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3333
LONG WINAPI RegOpenKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3268
LONG WINAPI RegEnumValueW(_In_ HKEY hKey, _In_ DWORD index, _Out_ LPWSTR value, _Inout_ PDWORD val_count, _Reserved_ PDWORD reserved, _Out_opt_ PDWORD type, _Out_opt_ LPBYTE data, _Inout_opt_ PDWORD count)
Definition: reg.c:2830
LSTATUS WINAPI RegQueryValueW(HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count)
Definition: reg.c:4241
LONG WINAPI RegEnumKeyW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, DWORD cbName)
Definition: reg.c:2393
BOOL WINAPI GetUserNameW(LPWSTR lpszName, LPDWORD lpSize)
Definition: misc.c:291
BOOL WINAPI CreateProcessWithLogonW(_In_ LPCWSTR lpUsername, _In_opt_ LPCWSTR lpDomain, _In_ LPCWSTR lpPassword, _In_ DWORD dwLogonFlags, _In_opt_ LPCWSTR lpApplicationName, _Inout_opt_ LPWSTR lpCommandLine, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCWSTR lpCurrentDirectory, _In_ LPSTARTUPINFOW lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation)
Definition: security.c:3728
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
Definition: string.c:464
INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
Definition: string.c:307
LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
Definition: string.c:380
INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
Definition: string.c:500
#define CloseHandle
Definition: compat.h:739
#define wcschr
Definition: compat.h:17
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:756
#define wcsrchr
Definition: compat.h:16
#define CP_ACP
Definition: compat.h:109
#define GetEnvironmentVariableW(x, y, z)
Definition: compat.h:755
#define SetLastError(x)
Definition: compat.h:752
#define ERROR_NOT_SUPPORTED
Definition: compat.h:100
#define MAX_PATH
Definition: compat.h:34
#define CALLBACK
Definition: compat.h:35
#define lstrcpyW
Definition: compat.h:749
#define WideCharToMultiByte
Definition: compat.h:111
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
#define lstrcpynW
Definition: compat.h:738
#define lstrlenW
Definition: compat.h:750
static const WCHAR *const ext[]
Definition: module.c:53
BOOL WINAPI FreeEnvironmentStringsW(IN LPWSTR EnvironmentStrings)
Definition: environ.c:389
DWORD WINAPI ExpandEnvironmentStringsW(IN LPCWSTR lpSrc, IN LPWSTR lpDst, IN DWORD nSize)
Definition: environ.c:519
VOID WINAPI RaiseException(_In_ DWORD dwExceptionCode, _In_ DWORD dwExceptionFlags, _In_ DWORD nNumberOfArguments, _In_opt_ const ULONG_PTR *lpArguments)
Definition: except.c:700
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:600
BOOL WINAPI SetCurrentDirectoryW(IN LPCWSTR lpPathName)
Definition: path.c:2249
DWORD WINAPI SearchPathW(IN LPCWSTR lpPath OPTIONAL, IN LPCWSTR lpFileName, IN LPCWSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart OPTIONAL)
Definition: path.c:1298
DWORD WINAPI GetShortPathNameW(IN LPCWSTR lpszLongPath, OUT LPWSTR lpszShortPath, IN DWORD cchBuffer)
Definition: path.c:1833
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
BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
Definition: proc.c:4600
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1489
BOOL WINAPI GetBinaryTypeW(LPCWSTR lpApplicationName, LPDWORD lpBinaryType)
Definition: vdm.c:1243
INT WINAPI GetProfileStringW(LPCWSTR section, LPCWSTR entry, LPCWSTR def_val, LPWSTR buffer, UINT len)
Definition: profile.c:1267
DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:583
int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4265
void WINAPI PathRemoveBlanksW(WCHAR *path)
Definition: path.c:1910
void WINAPI PathUnquoteSpacesW(WCHAR *path)
Definition: path.c:2006
int WINAPI PathGetDriveNumberW(const WCHAR *path)
Definition: path.c:1810
HRESULT WINAPI PathCreateFromUrlW(const WCHAR *url, WCHAR *path, DWORD *pcchPath, DWORD dwReserved)
Definition: path.c:3073
WCHAR *WINAPI PathFindFileNameW(const WCHAR *path)
Definition: path.c:1701
BOOL WINAPI UrlIsW(const WCHAR *url, URLIS Urlis)
Definition: path.c:4812
LPWSTR WINAPI PathFindExtensionW(const WCHAR *path)
Definition: path.c:1274
BOOL WINAPI PathIsRelativeW(const WCHAR *path)
Definition: path.c:1030
BOOL WINAPI PathStripToRootW(WCHAR *path)
Definition: path.c:1195
BOOL WINAPI PathIsURLW(const WCHAR *path)
Definition: path.c:3238
WCHAR *WINAPI PathGetArgsW(const WCHAR *path)
Definition: path.c:1740
BOOL WINAPI PathFileExistsW(const WCHAR *path)
Definition: path.c:2607
LPWSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsW(void)
Definition: process.c:1538
BOOL WINAPI SHRegGetBoolUSValueW(const WCHAR *subkey, const WCHAR *value, BOOL ignore_hkcu, BOOL default_value)
Definition: registry.c:4139
BOOL WINAPI StrToIntExW(const WCHAR *str, DWORD flags, INT *ret)
Definition: string.c:972
INT WINAPI DECLSPEC_HOTPATCH LoadStringW(HINSTANCE instance, UINT resource_id, LPWSTR buffer, INT buflen)
Definition: string.c:1220
BOOL WINAPI StrTrimW(WCHAR *str, const WCHAR *trim)
Definition: string.c:796
LPWSTR WINAPI CharLowerW(WCHAR *str)
Definition: string.c:1092
WCHAR *WINAPI StrDupW(const WCHAR *str)
Definition: string.c:313
int WINAPI StrCmpIW(const WCHAR *str, const WCHAR *comp)
Definition: string.c:456
WCHAR *WINAPI StrCpyNW(WCHAR *dst, const WCHAR *src, int count)
Definition: string.c:462
GUID guid
Definition: version.c:147
DWORD WINAPI GetVersion(void)
Definition: version.c:1458
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv)
Definition: compobj.c:3325
HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id)
Definition: compobj.c:2338
void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
Definition: compobj.c:2067
#define VERBKEY_CCHMAX
Definition: precomp.h:130
HRESULT SHGetNameAndFlagsW(_In_ LPCITEMIDLIST pidl, _In_ DWORD dwFlags, _Out_opt_ LPWSTR pszText, _In_ UINT cchBuf, _Inout_opt_ DWORD *pdwAttributes)
Definition: utils.cpp:503
EXTERN_C HRESULT SHELL_GetUIObjectOfAbsoluteItem(_In_opt_ HWND hWnd, _In_ PCIDLIST_ABSOLUTE pidl, _In_ REFIID riid, _Out_ void **ppvObj)
Definition: utils.cpp:380
HRESULT SHCoInitializeAnyApartment(VOID)
Definition: utils.cpp:494
void WINAPI SHFree(LPVOID pv)
Definition: shellole.c:370
HRESULT WINAPI SHExtCoCreateInstance(_In_opt_ LPCWSTR aclsid, _In_opt_ const CLSID *clsid, _In_opt_ LPUNKNOWN pUnkOuter, _In_ REFIID riid, _Out_ LPVOID *ppv)
Definition: shellole.c:222
BOOL WINAPI PathResolveW(_Inout_ LPWSTR path, _Inout_opt_ LPCWSTR *dirs, _In_ DWORD flags)
Definition: shellpath.c:1032
DWORD WINAPI SHGetAppCompatFlags(_In_ DWORD dwMask)
Definition: appcompat.c:433
HRESULT WINAPI AssocQueryStringW(ASSOCF cfFlags, ASSOCSTR str, LPCWSTR pszAssoc, LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut)
Definition: assoc.c:441
HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId)
Definition: ordinal.c:169
PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:259
BOOL WINAPI SHUnlockShared(LPVOID lpView)
Definition: ordinal.c:295
void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
Definition: path.c:779
BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs)
Definition: path.c:1409
BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, DWORD dwWhich)
Definition: path.c:1357
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1729
#define FAILED_UNEXPECTEDLY
Definition: utils.cpp:30
#define swprintf
Definition: precomp.h:40
#define assert(x)
Definition: debug.h:53
static void *static void *static LPDIRECTPLAY IUnknown * pUnk
Definition: dplayx.c:30
return ret
Definition: mutex.c:146
#define L(x)
Definition: resources.c:13
HINSTANCE hInst
Definition: dxdiag.c:13
static IShellFolder IShellItem **static IBindCtx LPITEMIDLIST SFGAOF
Definition: ebrowser.c:83
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FxAutoRegKey hKey
size_t total
GLuint start
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLsizei const GLchar *const * strings
Definition: glext.h:7622
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
GLenum const GLfloat * params
Definition: glext.h:5645
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLfloat param
Definition: glext.h:5796
GLenum GLsizei len
Definition: glext.h:6722
const GLint * attribs
Definition: glext.h:10538
GLenum target
Definition: glext.h:7315
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define DbgPrint
Definition: hal.h:12
#define iswspace(_c)
Definition: ctype.h:669
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
static TfClientId tid
nsresult QueryInterface(nsIIDRef riid, void **result)
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
const char * filename
Definition: ioapi.h:137
#define LOBYTE(W)
Definition: jmemdos.c:487
#define debugstr_guid
Definition: kernel32.h:35
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_w
Definition: kernel32.h:32
#define wine_dbgstr_w
Definition: kernel32.h:34
#define REG_SZ
Definition: layer.c:22
_In_ BOOL _In_ HANDLE hProcess
Definition: mapping.h:71
#define ZeroMemory
Definition: minwinbase.h:31
#define EXCEPTION_ACCESS_VIOLATION
Definition: minwinbase.h:44
LONG_PTR LPARAM
Definition: minwindef.h:175
LONG_PTR LRESULT
Definition: minwindef.h:176
UINT_PTR WPARAM
Definition: minwindef.h:174
#define error(str)
Definition: mkdosfs.c:1605
#define pch(ap)
Definition: match.c:418
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
LPCWSTR LPCWSTR LPCWSTR DWORD dwFlags
Definition: env.c:37
LPCWSTR szPath
Definition: env.c:37
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
static PVOID ptr
Definition: dispmode.c:27
static HINSTANCE hinst
Definition: edit.c:551
static IPrintDialogCallback callback
Definition: printdlg.c:326
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
static HMENU hmenu
Definition: win.c:66
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
HMONITOR WINAPI MonitorFromWindow(HWND, DWORD)
unsigned int UINT
Definition: ndis.h:50
#define _Out_opt_
Definition: no_sal2.h:214
#define _Inout_
Definition: no_sal2.h:162
#define _Out_writes_opt_(s)
Definition: no_sal2.h:226
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define KEY_READ
Definition: nt_native.h:1026
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define DBG_UNREFERENCED_LOCAL_VARIABLE(L)
Definition: ntbasedef.h:331
#define UNICODE_NULL
#define ANSI_NULL
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
#define PathAddExtensionW
Definition: pathcch.h:306
#define PathAddBackslashW
Definition: pathcch.h:302
#define STARTF_USEHOTKEY
Definition: pch.h:41
#define LOWORD(l)
Definition: pedump.c:82
long LONG
Definition: pedump.c:60
HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc, LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut)
Definition: pidl.c:1542
HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
Definition: pidl.c:1498
LPITEMIDLIST WINAPI ILCreateFromPathW(LPCWSTR path)
Definition: pidl.c:1102
static const WCHAR szName[]
Definition: powrprof.c:45
struct _STARTUPINFOW STARTUPINFOW
static const char topic[]
Definition: propsys.c:45
@ URLIS_APPLIABLE
Definition: shlwapi.h:601
#define UrlIsFileUrlW(x)
Definition: shlwapi.h:643
#define STIF_SUPPORT_HEX
Definition: shlwapi.h:1059
@ ASSOCSTR_COMMAND
Definition: shlwapi.h:886
@ ASSOCSTR_EXECUTABLE
Definition: shlwapi.h:887
@ ASSOCF_NONE
Definition: shlwapi.h:858
_In_ INT cchDest
Definition: shlwapi.h:1151
#define err(...)
#define REGSTR_PATH_EXPLORER
Definition: regstr.h:33
WCHAR classname[128]
Definition: startup.c:15
const WCHAR * str
@ Cmd
Definition: sacdrv.h:278
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
#define memset(x, y, z)
Definition: compat.h:39
BOOL HCR_GetDefaultVerbW(HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len)
Definition: classes.c:152
BOOL HCR_GetExecuteCommandW(HKEY hkeyClass, LPCWSTR szClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len)
Definition: classes.c:220
HRESULT HCR_GetProgIdKeyOfExtension(PCWSTR szExtension, PHKEY phKey, BOOL AllowFallback)
Definition: classes.c:55
static __inline void __SHCloneStrWtoA(char **target, const WCHAR *source)
Definition: shell32_main.h:191
DWORD SH32_InternalRestricted(DWORD rest)
Definition: shpolicy.c:180
static __inline LPWSTR __SHCloneStrAtoW(WCHAR **target, const char *source)
Definition: shell32_main.h:204
@ REST_SH32_ENABLESHELLEXECUTEHOOKS
Definition: shell32_main.h:41
static __inline void __SHCloneStrW(WCHAR **target, const WCHAR *source)
Definition: shell32_main.h:198
#define SEE_MASK_FLAG_LOG_USAGE
Definition: shellapi.h:55
#define SEE_MASK_DOENVSUBST
Definition: shellapi.h:37
#define SE_ERR_SHARE
Definition: shellapi.h:130
_In_ UINT _In_ UINT cch
Definition: shellapi.h:432
#define SEE_MASK_CLASSKEY
Definition: shellapi.h:26
#define SEE_MASK_HOTKEY
Definition: shellapi.h:32
#define SEE_MASK_NOCLOSEPROCESS
Definition: shellapi.h:33
#define SE_ERR_PNF
Definition: shellapi.h:126
struct _SHELLEXECUTEINFOW SHELLEXECUTEINFOW
#define SEE_MASK_HMONITOR
Definition: shellapi.h:45
#define SEE_MASK_CLASSNAME
Definition: shellapi.h:25
#define SEE_MASK_ASYNCOK
Definition: shellapi.h:43
#define SEE_MASK_IDLIST
Definition: shellapi.h:27
#define SEE_MASK_NOASYNC
Definition: shellapi.h:35
#define SE_ERR_ACCESSDENIED
Definition: shellapi.h:127
#define SE_ERR_DLLNOTFOUND
Definition: shellapi.h:129
#define SEE_MASK_WAITFORINPUTIDLE
Definition: shellapi.h:52
#define SEE_MASK_FLAG_DDEWAIT
Definition: shellapi.h:36
#define SEE_MASK_CONNECTNETDRV
Definition: shellapi.h:34
_In_opt_ LPCSTR lpDirectory
Definition: shellapi.h:496
#define SE_ERR_OOM
Definition: shellapi.h:128
#define SEE_MASK_INVOKEIDLIST
Definition: shellapi.h:28
#define SE_ERR_FNF
Definition: shellapi.h:125
#define SE_ERR_DDEBUSY
Definition: shellapi.h:134
#define SEE_MASK_FLAG_NO_UI
Definition: shellapi.h:38
#define SE_ERR_NOASSOC
Definition: shellapi.h:135
#define SE_ERR_DDETIMEOUT
Definition: shellapi.h:132
#define SEE_MASK_NO_CONSOLE
Definition: shellapi.h:41
#define SE_ERR_DDEFAIL
Definition: shellapi.h:133
#define ILGetSize
Definition: shellclasses.h:638
LONG WINAPI SHRegQueryValueExW(HKEY hkey, LPCWSTR pszValue, LPDWORD pdwReserved, LPDWORD pdwType, LPVOID pvData, LPDWORD pcbData)
Definition: shellreg.c:108
BOOL WINAPI StrRetToStrNW(LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
Definition: shellstring.c:85
#define SHELL_ErrorBox
Definition: shellutils.h:126
static DWORD ddeInst
Definition: shlexec.c:147
static HSZ hszTopic
Definition: shlexec.c:148
static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
Definition: shlexec.cpp:1930
static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:1819
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExA(LPSHELLEXECUTEINFOA sei)
Definition: shlexec.cpp:2665
static UINT_PTR InvokeOpenWith(HWND hWndOwner, SHELLEXECUTEINFOW &sei)
Definition: shlexec.cpp:86
EXTERN_C VOID WINAPI ShellExec_RunDLLW(_In_opt_ HWND hwnd, _In_opt_ HINSTANCE hInstance, _In_ PCWSTR pszCmdLine, _In_ INT nCmdShow)
Definition: shlexec.cpp:3430
HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
Definition: shlexec.cpp:1581
static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:1746
static HRESULT PromptAndRunProcessAs(_In_opt_ HWND hwnd, _In_ LPWSTR Cmd, _In_ DWORD CreationFlags, _In_opt_ LPWSTR Env, _In_opt_ LPCWSTR Dir, _In_ STARTUPINFOW *pSI, _Out_ PROCESS_INFORMATION *pPI)
Definition: shlexec.cpp:661
static void do_error_dialog(UINT_PTR retval, HWND hwnd, PCWSTR filename)
Definition: shlexec.cpp:2167
static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
Definition: shlexec.cpp:150
static BOOL SHELL_InvokePidl(_In_ LPSHELLEXECUTEINFOW sei, _In_ LPCITEMIDLIST pidl)
Definition: shlexec.cpp:2045
EXTERN_C void WINAPI OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow)
Definition: shlexec.cpp:2855
static LPCWSTR SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0)
Definition: shlexec.cpp:2869
EXTERN_C HINSTANCE WINAPI RealShellExecuteExW(_In_opt_ HWND hwnd, _In_opt_ LPCWSTR lpOperation, _In_opt_ LPCWSTR lpFile, _In_opt_ LPCWSTR lpParameters, _In_opt_ LPCWSTR lpDirectory, _In_opt_ LPWSTR lpReturn, _In_opt_ LPCWSTR lpTitle, _In_opt_ LPVOID lpReserved, _In_ INT nCmdShow, _Out_opt_ PHANDLE lphProcess, _In_ DWORD dwFlags)
Definition: shlexec.cpp:3110
static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWSTR szCommandline, LPCWSTR executable_name, SHELL_ExecuteW32 execfunc, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out)
Definition: shlexec.cpp:1479
static INT_PTR CALLBACK RunAsDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: shlexec.cpp:596
EXTERN_C void WINAPI OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow)
Definition: shlexec.cpp:2844
static LONG ShellExecute_FromContextMenuHandlers(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:1885
static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args)
Definition: shlexec.cpp:1034
static DWORD ShellExecute_Normal(_Inout_ LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2637
EXTERN_C VOID WINAPI ShellExec_RunDLLA(_In_opt_ HWND hwnd, _In_opt_ HINSTANCE hInstance, _In_ PCSTR pszCmdLine, _In_ INT nCmdShow)
Definition: shlexec.cpp:3413
EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback)
Definition: shlexec.cpp:2809
static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
Definition: shlexec.cpp:2209
static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv, HSZ hsz1, HSZ hsz2, HDDEDATA hData, ULONG_PTR dwData1, ULONG_PTR dwData2)
Definition: shlexec.cpp:1252
static BOOL SHELL_ArgifyW(WCHAR *out, DWORD len, const WCHAR *fmt, const WCHAR *lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD *out_len, const WCHAR *lpDir)
Definition: shlexec.cpp:299
#define SEE_MASK_CLASSALL
Definition: shlexec.cpp:31
static WCHAR * expand_environment(const WCHAR *str)
Definition: shlexec.cpp:2188
static HRESULT TryShellExecuteHooks(LPSHELLEXECUTEINFOW pSEI)
Definition: shlexec.cpp:122
HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
Definition: shlexec.cpp:1538
static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
Definition: shlexec.cpp:2133
EXTERN_C LONG PathProcessCommandW(_In_ PCWSTR pszSrc, _Out_writes_opt_(dwBuffSize) PWSTR pszDest, _In_ INT cchDest, _In_ DWORD dwFlags)
Definition: shlexec.cpp:3239
struct _RUNASDLGDATA RUNASDLGDATA
static unsigned dde_connect(const WCHAR *key, const WCHAR *start, WCHAR *ddeexec, const WCHAR *lpFile, WCHAR *env, LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc, const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
Definition: shlexec.cpp:1270
static VOID ShellExecute_ShowError(_In_ const SHELLEXECUTEINFOW *ExecInfo, _In_opt_ LPCWSTR pszCaption, _In_ DWORD dwError)
Definition: shlexec.cpp:2651
EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath)
Definition: shellpath.c:539
static HRESULT shellex_run_context_menu_default(IShellExtInit *obj, LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:1677
static HRESULT InvokeShellExecuteHook(PCWSTR pszClsid, LPSHELLEXECUTEINFOW pSEI)
Definition: shlexec.cpp:99
HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
Definition: shlexec.cpp:2778
static UINT SHELL_FindExecutableByVerb(LPCWSTR lpVerb, LPWSTR key, LPWSTR classname, LPWSTR command, LONG commandlen)
Definition: shlexec.cpp:966
static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
Definition: shlexec.cpp:725
static BOOL SHELL_InRunDllProcess(VOID)
Definition: shlexec.cpp:73
static HWND SHELL_GetUsableDialogOwner(HWND hWnd)
Definition: shlexec.cpp:569
static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen)
Definition: shlexec.cpp:1989
static HKEY ShellExecute_GetClassKey(const SHELLEXECUTEINFOW *sei)
Definition: shlexec.cpp:1633
static HRESULT shellex_get_contextmenu(LPSHELLEXECUTEINFOW sei, CComPtr< IContextMenu > &cm)
Definition: shlexec.cpp:1780
EXTERN_C HINSTANCE WINAPI RealShellExecuteA(_In_opt_ HWND hwnd, _In_opt_ LPCSTR lpOperation, _In_opt_ LPCSTR lpFile, _In_opt_ LPCSTR lpParameters, _In_opt_ LPCSTR lpDirectory, _In_opt_ LPSTR lpReturn, _In_opt_ LPCSTR lpTitle, _In_opt_ LPVOID lpReserved, _In_ INT nCmdShow, _Out_opt_ PHANDLE lphProcess)
Definition: shlexec.cpp:3177
static HRESULT shellex_get_dataobj(LPSHELLEXECUTEINFOW sei, CComPtr< IDataObject > &dataObj)
Definition: shlexec.cpp:1652
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2723
static VOID ShellExec_RunDLL_Helper(_In_opt_ HWND hwnd, _In_opt_ HINSTANCE hInstance, _In_ PCWSTR pszCmdLine, _In_ INT nCmdShow)
Definition: shlexec.cpp:3355
static LPWSTR SHELL_BuildEnvW(const WCHAR *path)
Definition: shlexec.cpp:848
UINT_PTR(* SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out)
Definition: shlexec.cpp:33
static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR pszPath, UINT uOutSize)
Definition: shlexec.cpp:551
static void ParseTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
Definition: shlexec.cpp:217
HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
Definition: shlexec.cpp:2607
EXTERN_C HINSTANCE WINAPI RealShellExecuteExA(_In_opt_ HWND hwnd, _In_opt_ LPCSTR lpOperation, _In_opt_ LPCSTR lpFile, _In_opt_ LPCSTR lpParameters, _In_opt_ LPCSTR lpDirectory, _In_opt_ LPSTR lpReturn, _In_opt_ LPCSTR lpTitle, _In_opt_ LPVOID lpReserved, _In_ INT nCmdShow, _Out_opt_ PHANDLE lphProcess, _In_ DWORD dwFlags)
Definition: shlexec.cpp:3043
static BOOL SHELL_TryAppPathW(LPCWSTR szName, LPWSTR lpResult, WCHAR **env)
Definition: shlexec.cpp:906
static int Win32ErrFromHInst(HINSTANCE hInst)
Definition: shlexec.cpp:36
static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
Definition: shlexec.cpp:2097
EXTERN_C HINSTANCE WINAPI RealShellExecuteW(_In_opt_ HWND hwnd, _In_opt_ LPCWSTR lpOperation, _In_opt_ LPCWSTR lpFile, _In_opt_ LPCWSTR lpParameters, _In_opt_ LPCWSTR lpDirectory, _In_opt_ LPWSTR lpReturn, _In_opt_ LPCWSTR lpTitle, _In_opt_ LPVOID lpReserved, _In_ INT nCmdShow, _Out_opt_ PHANDLE lphProcess)
Definition: shlexec.cpp:3207
HRESULT hr
Definition: shlfolder.c:183
#define PPCF_FORCEQUALIFY
Definition: shlobj.h:2427
#define PPCF_INCLUDEARGS
Definition: shlobj.h:2423
#define PPCF_LONGESTPOSSIBLE
Definition: shlobj.h:2428
@ OAIF_EXEC
Definition: shlobj.h:2688
@ OAIF_REGISTER_EXT
Definition: shlobj.h:2687
@ OAIF_ALLOW_REGISTRATION
Definition: shlobj.h:2686
#define PPCF_ADDQUOTES
Definition: shlobj.h:2422
#define PPCF_ADDARGUMENTS
Definition: shlobj.h:2424
#define PPCF_NODIRECTORIES
Definition: shlobj.h:2425
#define WHICH_DEFAULT
#define SHACF_WIN95SHLEXEC
#define IDS_FILE_NOT_FOUND
Definition: shresdef.h:373
#define IDD_RUN_AS
Definition: shresdef.h:403
#define IDC_RUNAS_PWD
Definition: shresdef.h:409
#define IDC_RUNAS_CURRENT
Definition: shresdef.h:404
#define IDC_RUNAS_OTHER
Definition: shresdef.h:405
#define IDC_RUNAS_SAFER
Definition: shresdef.h:406
#define IDC_RUNAS_NAME
Definition: shresdef.h:407
#define IDS_SHLEXEC_NOASSOC
Definition: shresdef.h:187
#define IDC_RUNAS_BROWSE
Definition: shresdef.h:408
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
TCHAR * cmdline
Definition: stretchblt.cpp:32
STRSAFEAPI StringCchPrintfW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:530
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
UINT LogonFlags
Definition: shlexec.cpp:588
WCHAR Password[MAX_PATH]
Definition: shlexec.cpp:590
WCHAR NameBuffer[MAX_PATH]
Definition: shlexec.cpp:589
LPWSTR Name
Definition: shlexec.cpp:586
LPWSTR Domain
Definition: shlexec.cpp:586
LPCSTR lpParameters
Definition: shellapi.h:316
HINSTANCE hInstApp
Definition: shellapi.h:319
LPCSTR lpDirectory
Definition: shellapi.h:317
LPCWSTR lpDirectory
Definition: shellapi.h:340
HINSTANCE hInstApp
Definition: shellapi.h:342
LPCWSTR lpParameters
Definition: shellapi.h:339
Definition: match.c:390
Definition: cookie.c:202
Definition: ftp_var.h:139
Definition: dsound.c:943
Definition: copy.c:22
#define EXCEPTION_NONCONTINUABLE
Definition: stubs.h:23
#define max(a, b)
Definition: svc.c:63
#define LANG_USER_DEFAULT
Definition: tnerror.cpp:50
#define DWORD_PTR
Definition: treelist.c:76
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
HANDLE HINSTANCE
Definition: typedefs.h:77
uint16_t * PWSTR
Definition: typedefs.h:56
int32_t INT_PTR
Definition: typedefs.h:64
const uint16_t * PCWSTR
Definition: typedefs.h:57
uint32_t DWORD_PTR
Definition: typedefs.h:65
unsigned char * LPBYTE
Definition: typedefs.h:53
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
const char * PCSTR
Definition: typedefs.h:52
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
#define SEE_MASK_USE_RESERVED
Definition: undocshell.h:694
#define SEE_MASK_FLAG_SEPVDM
Definition: undocshell.h:693
#define SEE_MASK_HASTITLE
Definition: undocshell.h:695
#define SEE_MASK_NO_HOOKS
Definition: undocshell.h:691
#define SEE_MASK_UNKNOWN_0x1000
Definition: undocshell.h:690
#define SEE_MASK_HASLINKNAME
Definition: undocshell.h:692
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
int retval
Definition: wcstombs.cpp:91
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
static int error_code[8]
Definition: odbccp32.c:61
HWND WINAPI GetShellWindow(void)
Definition: input.c:974
#define LOGON_WITH_PROFILE
Definition: winbase.h:598
#define SecureZeroMemory
Definition: winbase.h:1461
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define STARTF_USESHOWWINDOW
Definition: winbase.h:468
#define CREATE_UNICODE_ENVIRONMENT
Definition: winbase.h:190
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:400
#define CREATE_SEPARATE_WOW_VDM
Definition: winbase.h:191
#define FORMAT_MESSAGE_ARGUMENT_ARRAY
Definition: winbase.h:401
#define WAIT_FAILED
Definition: winbase.h:390
#define LOGON_NETCREDENTIALS_ONLY
Definition: winbase.h:599
#define CREATE_NEW_CONSOLE
Definition: winbase.h:184
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
#define WINAPI
Definition: msvc.h:6
#define strncmpiW(s1, s2, n)
Definition: unicode.h:46
#define strstrW(d, s)
Definition: unicode.h:38
#define strchrW(s, c)
Definition: unicode.h:40
#define strlenW(s)
Definition: unicode.h:34
#define strrchrW(s, c)
Definition: unicode.h:41
#define strcatW(d, s)
Definition: unicode.h:36
#define isspaceW(n)
Definition: unicode.h:58
#define strcpyW(d, s)
Definition: unicode.h:35
#define S_FALSE
Definition: winerror.h:3451
static HRESULT HRESULT_FROM_WIN32(unsigned int x)
Definition: winerror.h:210
#define ERROR_APP_WRONG_OS
Definition: winerror.h:997
#define ERROR_INVALID_LOGON_HOURS
Definition: winerror.h:1155
#define ERROR_SHARING_VIOLATION
Definition: winerror.h:257
#define ERROR_RMODE_APP
Definition: winerror.h:999
#define ERROR_ACCOUNT_RESTRICTION
Definition: winerror.h:1154
#define ERROR_LOGON_FAILURE
Definition: winerror.h:1153
#define ERROR_INVALID_ACCOUNT_NAME
Definition: winerror.h:1142
#define ERROR_DDE_FAIL
Definition: winerror.h:1002
#define ERROR_DLL_NOT_FOUND
Definition: winerror.h:1003
#define ERROR_NO_ASSOCIATION
Definition: winerror.h:1001
#define ERROR_INVALID_DLL
Definition: winerror.h:1000
#define ERROR_CANCELLED
Definition: winerror.h:1055
#define CO_E_APPNOTFOUND
Definition: winerror.h:3921
#define ERROR_SINGLE_INSTANCE_APP
Definition: winerror.h:998
#define ERROR_BAD_FORMAT
Definition: winerror.h:236
#define ERROR_OLD_WIN_VERSION
Definition: winerror.h:996
#define ERROR_ACCOUNT_DISABLED
Definition: winerror.h:1158
#define ERROR_NO_SUCH_USER
Definition: winerror.h:1144
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:1333
#define ERROR_PASSWORD_EXPIRED
Definition: winerror.h:1157
_In_ DWORD _In_ int _In_ int _In_opt_ LPNLSVERSIONINFO _In_opt_ LPVOID lpReserved
Definition: winnls.h:1268
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define HKEY_CLASSES_ROOT
Definition: winreg.h:10
#define SW_SHOWNORMAL
Definition: winuser.h:781
#define SW_SHOWMAXIMIZED
Definition: winuser.h:784
HMENU WINAPI CreatePopupMenu(void)
Definition: menu.c:838
UINT WINAPI GetMenuDefaultItem(_In_ HMENU hMenu, _In_ UINT fByPos, _In_ UINT gmdiFlags)
#define EM_LIMITTEXT
Definition: winuser.h:2029
#define MIIM_STRING
Definition: winuser.h:738
#define DWLP_USER
Definition: winuser.h:883
#define GetWindowLongPtrW
Definition: winuser.h:4931
#define MIIM_ID
Definition: winuser.h:733
int WINAPI GetMenuItemCount(_In_opt_ HMENU)
#define IDCANCEL
Definition: winuser.h:842
HMENU WINAPI CreateMenu(void)
Definition: menu.c:829
#define WM_COMMAND
Definition: winuser.h:1768
#define MIIM_FTYPE
Definition: winuser.h:740
#define CB_SETCURSEL
Definition: winuser.h:1990
#define WM_GETTEXT
Definition: winuser.h:1646
#define WM_INITDIALOG
Definition: winuser.h:1767
int WINAPI MessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType)
HWND WINAPI GetDlgItem(_In_opt_ HWND, _In_ int)
#define IDOK
Definition: winuser.h:841
#define MIIM_STATE
Definition: winuser.h:732
LRESULT WINAPI SendDlgItemMessageW(_In_ HWND, _In_ int, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define MFS_DEFAULT
Definition: winuser.h:759
HWND WINAPI GetDesktopWindow(void)
Definition: window.c:628
#define SW_SHOWDEFAULT
Definition: winuser.h:791
#define MB_ICONERROR
Definition: winuser.h:798
UINT WINAPI IsDlgButtonChecked(_In_ HWND, _In_ int)
#define WM_SETTEXT
Definition: winuser.h:1645
BOOL WINAPI IsChild(_In_ HWND, _In_ HWND)
#define BM_CLICK
Definition: winuser.h:1946
#define CB_ADDSTRING
Definition: winuser.h:1965
DWORD WINAPI WaitForInputIdle(_In_ HANDLE, _In_ DWORD)
#define MAKEINTRESOURCEA(i)
Definition: winuser.h:581
BOOL WINAPI DestroyMenu(_In_ HMENU)
BOOL WINAPI GetMenuItemInfoW(_In_ HMENU, _In_ UINT, _In_ BOOL, _Inout_ LPMENUITEMINFOW)
#define SW_RESTORE
Definition: winuser.h:790
#define VK_SHIFT
Definition: winuser.h:2238
#define SW_SHOW
Definition: winuser.h:786
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define SetWindowLongPtrW
Definition: winuser.h:5457
BOOL WINAPI IsWindowVisible(_In_ HWND)
#define MIIM_DATA
Definition: winuser.h:737
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
SHORT WINAPI GetKeyState(_In_ int)
INT_PTR WINAPI DialogBoxParamW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_opt_ HWND, _In_opt_ DLGPROC, _In_ LPARAM)
BOOL WINAPI EndDialog(_In_ HWND, _In_ INT_PTR)
#define IID_PPV_ARG(Itype, ppType)
#define IID_NULL_PPV_ARG(Itype, ppType)
const char * LPCSTR
Definition: xmlstorage.h:183
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
char * LPSTR
Definition: xmlstorage.h:182