ReactOS 0.4.16-dev-1537-g4e425b5
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
569/*************************************************************************
570 * SHELL_ExecuteW [Internal]
571 *
572 */
573static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
574 const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
575{
579 UINT gcdret = 0;
580 WCHAR curdir[MAX_PATH];
581 DWORD dwCreationFlags;
582 const WCHAR *lpDirectory = NULL;
583
584 TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory));
585
586 /* make sure we don't fail the CreateProcess if the calling app passes in
587 * a bad working directory */
588 if (!StrIsNullOrEmpty(psei->lpDirectory))
589 {
592 lpDirectory = psei->lpDirectory;
593 }
594
595 /* ShellExecute specifies the command from psei->lpDirectory
596 * if present. Not from the current dir as CreateProcess does */
597 if (lpDirectory)
598 if ((gcdret = GetCurrentDirectoryW( MAX_PATH, curdir)))
600 ERR("cannot set directory %s\n", debugstr_w(lpDirectory));
601
603 startup.cb = sizeof(STARTUPINFOW);
605 startup.wShowWindow = psei->nShow;
606 dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
607 if (!(psei->fMask & SEE_MASK_NO_CONSOLE))
608 dwCreationFlags |= CREATE_NEW_CONSOLE;
609 if (psei->fMask & SEE_MASK_FLAG_SEPVDM)
610 dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
611 startup.lpTitle = (LPWSTR)(psei->fMask & (SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE) ? psei->lpClass : NULL);
612
613 if (psei->fMask & SEE_MASK_HASLINKNAME)
614 startup.dwFlags |= STARTF_TITLEISLINKNAME;
615
616 if (psei->fMask & SEE_MASK_HOTKEY)
617 {
618 startup.hStdInput = UlongToHandle(psei->dwHotKey);
619 startup.dwFlags |= STARTF_USEHOTKEY;
620 }
621
622 if (psei->fMask & SEE_MASK_ICON) // hIcon has higher precedence than hMonitor
623 {
624 startup.hStdOutput = psei->hIcon;
625 startup.dwFlags |= STARTF_SHELLPRIVATE;
626 }
627 else if ((psei->fMask & SEE_MASK_HMONITOR) || psei->hwnd)
628 {
629 if (psei->fMask & SEE_MASK_HMONITOR)
630 startup.hStdOutput = psei->hMonitor;
631 else if (psei->hwnd)
632 startup.hStdOutput = MonitorFromWindow(psei->hwnd, MONITOR_DEFAULTTONEAREST);
633 if (startup.hStdOutput)
634 startup.dwFlags |= STARTF_SHELLPRIVATE;
635 }
636
637 if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
639 {
640 /* Give 30 seconds to the app to come up, if desired. Probably only needed
641 when starting app immediately before making a DDE connection. */
642 if (shWait)
643 if (WaitForInputIdle(info.hProcess, 30000) == WAIT_FAILED)
644 WARN("WaitForInputIdle failed: Error %d\n", GetLastError() );
645 retval = 33;
646
647 if (psei->fMask & SEE_MASK_NOCLOSEPROCESS)
648 psei_out->hProcess = info.hProcess;
649 else
650 CloseHandle( info.hProcess );
651 CloseHandle( info.hThread );
652 }
653 else if ((retval = GetLastError()) >= 32)
654 {
655 WARN("CreateProcess returned error %ld\n", retval);
657 }
658
659 TRACE("returning %lu\n", retval);
660
661 psei_out->hInstApp = (HINSTANCE)retval;
662
663 if (gcdret)
664 if (!SetCurrentDirectoryW(curdir))
665 ERR("cannot return to directory %s\n", debugstr_w(curdir));
666
667 return retval;
668}
669
670
671/***********************************************************************
672 * SHELL_BuildEnvW [Internal]
673 *
674 * Build the environment for the new process, adding the specified
675 * path to the PATH variable. Returned pointer must be freed by caller.
676 */
678{
680 WCHAR *strings, *p, *p2;
681 int total = wcslen(path) + 1;
682 BOOL got_path = FALSE;
683
684 if (!(strings = GetEnvironmentStringsW())) return NULL;
685 p = strings;
686 while (*p)
687 {
688 int len = wcslen(p) + 1;
689 if (!_wcsnicmp( p, L"PATH=", 5 )) got_path = TRUE;
690 total += len;
691 p += len;
692 }
693 if (!got_path) total += 5; /* we need to create PATH */
694 total++; /* terminating null */
695
696 if (!new_env.Allocate(total))
697 {
699 return NULL;
700 }
701 p = strings;
702 p2 = new_env;
703 while (*p)
704 {
705 int len = wcslen(p) + 1;
706 memcpy(p2, p, len * sizeof(WCHAR));
707 if (!_wcsnicmp( p, L"PATH=", 5 ))
708 {
709 p2[len - 1] = ';';
710 wcscpy( p2 + len, path );
711 p2 += wcslen(path) + 1;
712 }
713 p += len;
714 p2 += len;
715 }
716 if (!got_path)
717 {
718 wcscpy(p2, L"PATH=");
719 wcscat(p2, path);
720 p2 += wcslen(p2) + 1;
721 }
722 *p2 = 0;
724 return new_env.Detach();
725}
726
727/***********************************************************************
728 * SHELL_TryAppPathW [Internal]
729 *
730 * Helper function for SHELL_FindExecutable
731 * @param lpResult - pointer to a buffer of size MAX_PATH
732 * On entry: szName is a filename (probably without path separators).
733 * On exit: if szName found in "App Path", place full path in lpResult, and return true
734 */
736{
737 HKEY hkApp = NULL;
738 WCHAR buffer[1024];
739 DWORD len, dwType;
740 LONG res;
741 BOOL found = FALSE;
742
743 if (env) *env = NULL;
744 wcscpy(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
747 if (res)
748 {
749 // Add ".exe" extension, if extension does not exists
750 if (PathAddExtensionW(buffer, L".exe"))
751 {
753 }
754 if (res) goto end;
755 }
756
757 len = MAX_PATH * sizeof(WCHAR);
758 res = SHRegQueryValueExW(hkApp, NULL, NULL, &dwType, (LPBYTE)lpResult, &len);
759 if (res != ERROR_SUCCESS || dwType != REG_SZ)
760 goto end;
761
762 found = TRUE;
763
764 if (env)
765 {
766 len = sizeof(buffer);
767 res = SHRegQueryValueExW(hkApp, L"Path", NULL, &dwType, (LPBYTE)buffer, &len);
768 if (res == ERROR_SUCCESS && dwType == REG_SZ && buffer[0])
770 }
771
772end:
773 if (hkApp) RegCloseKey(hkApp);
774 return found;
775}
776
777/*************************************************************************
778 * SHELL_FindExecutableByVerb [Internal]
779 *
780 * called from SHELL_FindExecutable or SHELL_execute_class
781 * in/out:
782 * classname a buffer, big enough, to get the key name to do actually the
783 * command "WordPad.Document.1\\shell\\open\\command"
784 * passed as "WordPad.Document.1"
785 * in:
786 * lpVerb the operation on it (open)
787 * commandlen the size of command buffer (in bytes)
788 * out:
789 * command a buffer, to store the command to do the
790 * operation on the file
791 * key a buffer, big enough, to get the key name to do actually the
792 * command "WordPad.Document.1\\shell\\open\\command"
793 * Can be NULL
794 */
796{
797 HKEY hkeyClass;
798 WCHAR verb[MAX_PATH];
799
801 return SE_ERR_NOASSOC;
802 if (!HCR_GetDefaultVerbW(hkeyClass, lpVerb, verb, ARRAY_SIZE(verb)))
803 return SE_ERR_NOASSOC;
804 RegCloseKey(hkeyClass);
805
806 /* Looking for ...buffer\shell<verb>\command */
807 wcscat(classname, L"\\shell\\"); // FIXME: Use HCR_GetExecuteCommandW or AssocAPI
808 wcscat(classname, verb);
809 wcscat(classname, L"\\command");
810
812 &commandlen) == ERROR_SUCCESS)
813 {
814 commandlen /= sizeof(WCHAR);
815 if (key) wcscpy(key, classname);
816#if 0
817 LPWSTR tmp;
818 WCHAR param[256];
819 LONG paramlen = sizeof(param);
820
821 /* FIXME: it seems all Windows version don't behave the same here.
822 * the doc states that this ddeexec information can be found after
823 * the exec names.
824 * on Win98, it doesn't appear, but I think it does on Win2k
825 */
826 /* Get the parameters needed by the application
827 from the associated ddeexec key */
828 tmp = strstrW(classname, L"\\command");
829 tmp[0] = '\0';
830 wcscat(classname, wDdeexec);
832 &paramlen) == ERROR_SUCCESS)
833 {
834 paramlen /= sizeof(WCHAR);
835 wcscat(command, L" ");
837 commandlen += paramlen;
838 }
839#endif
840
841 command[commandlen] = '\0';
842
843 return 33; /* FIXME see SHELL_FindExecutable() */
844 }
845
846 return SE_ERR_NOASSOC;
847}
848
849/*************************************************************************
850 * SHELL_FindExecutable [Internal]
851 *
852 * Utility for code sharing between FindExecutable and ShellExecute
853 * in:
854 * lpFile the name of a file
855 * lpVerb the operation on it (open)
856 * out:
857 * lpResult a buffer, big enough :-(, to store the command to do the
858 * operation on the file
859 * key a buffer, big enough, to get the key name to do actually the
860 * command (it'll be used afterwards for more information
861 * on the operation)
862 */
863static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb,
864 LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args)
865{
866 WCHAR *extension = NULL; /* pointer to file extension */
867 WCHAR classname[256]; /* registry name for this file type */
868 LONG classnamelen = sizeof(classname); /* length of above */
869 WCHAR command[1024]; /* command from registry */
870 WCHAR wBuffer[256]; /* Used to GetProfileString */
872 WCHAR *tok; /* token pointer */
873 WCHAR xlpFile[MAX_PATH]; /* result of PathResolve */
874 DWORD attribs; /* file attributes */
875 WCHAR curdir[MAX_PATH];
876 const WCHAR *search_paths[3] = {0};
877
878 TRACE("%s\n", debugstr_w(lpFile));
879
880 if (!lpResult)
882
883 xlpFile[0] = '\0';
884 lpResult[0] = '\0'; /* Start off with an empty return string */
885 if (key) *key = '\0';
886
887 /* trap NULL parameters on entry */
888 if (!lpFile)
889 {
890 WARN("(lpFile=%s,lpResult=%s): NULL parameter\n",
891 debugstr_w(lpFile), debugstr_w(lpResult));
892 return ERROR_FILE_NOT_FOUND; /* File not found. Close enough, I guess. */
893 }
894
895 if (SHELL_TryAppPathW( lpFile, lpResult, env ))
896 {
897 TRACE("found %s via App Paths\n", debugstr_w(lpResult));
898 return 33;
899 }
900
901 GetCurrentDirectoryW(ARRAY_SIZE(curdir), curdir);
902 if (lpPath && *lpPath)
903 {
904 search_paths[0] = lpPath;
905 search_paths[1] = curdir;
906 }
907 else
908 {
909 search_paths[0] = curdir;
910 }
911
912 lstrcpyW(xlpFile, lpFile);
913 if (PathResolveW(xlpFile, search_paths, PRF_TRYPROGRAMEXTENSIONS | PRF_VERIFYEXISTS) ||
914 PathFindOnPathW(xlpFile, search_paths))
915 {
916 TRACE("PathResolveW returned non-zero\n");
917 lpFile = xlpFile;
918 PathRemoveBlanksW(xlpFile);
919
920 /* Clear any trailing periods */
921 SIZE_T i = wcslen(xlpFile);
922 while (i > 0 && xlpFile[i - 1] == '.')
923 {
924 xlpFile[--i] = '\0';
925 }
926
927 lstrcpyW(lpResult, xlpFile);
928 /* The file was found in lpPath or one of the directories in the system-wide search path */
929 }
930 else
931 {
932 xlpFile[0] = '\0';
933 }
934
935 attribs = GetFileAttributesW(lpFile);
937 {
938 wcscpy(classname, L"Folder");
939 }
940 else
941 {
942 /* Did we get something? Anything? */
943 if (xlpFile[0] == 0)
944 {
945 TRACE("Returning SE_ERR_FNF\n");
946 return SE_ERR_FNF;
947 }
948 /* First thing we need is the file's extension */
949 extension = wcsrchr(xlpFile, '.'); /* Assume last "." is the one; */
950 /* File->Run in progman uses */
951 /* .\FILE.EXE :( */
952 TRACE("xlpFile=%s,extension=%s\n", debugstr_w(xlpFile), debugstr_w(extension));
953
954 if (extension == NULL || extension[1] == 0)
955 {
956 WARN("Returning SE_ERR_NOASSOC\n");
957 return SE_ERR_NOASSOC;
958 }
959
960 /* Three places to check: */
961 /* 1. win.ini, [windows], programs (NB no leading '.') */
962 /* 2. Registry, HKEY_CLASS_ROOT<classname>\shell\open\command */
963 /* 3. win.ini, [extensions], extension (NB no leading '.' */
964 /* All I know of the order is that registry is checked before */
965 /* extensions; however, it'd make sense to check the programs */
966 /* section first, so that's what happens here. */
967
968 /* See if it's a program - if GetProfileString fails, we skip this
969 * section. Actually, if GetProfileString fails, we've probably
970 * got a lot more to worry about than running a program... */
971 if (GetProfileStringW(L"windows", L"programs", L"exe pif bat cmd com", wBuffer, ARRAY_SIZE(wBuffer)) > 0)
972 {
973 CharLowerW(wBuffer);
974 tok = wBuffer;
975 while (*tok)
976 {
977 WCHAR *p = tok;
978 while (*p && *p != ' ' && *p != '\t') p++;
979 if (*p)
980 {
981 *p++ = 0;
982 while (*p == ' ' || *p == '\t') p++;
983 }
984
985 if (_wcsicmp(tok, &extension[1]) == 0) /* have to skip the leading "." */
986 {
987 wcscpy(lpResult, xlpFile);
988 /* Need to perhaps check that the file has a path
989 * attached */
990 TRACE("found %s\n", debugstr_w(lpResult));
991 return 33;
992 /* Greater than 32 to indicate success */
993 }
994 tok = p;
995 }
996 }
997
998 /* Check registry */
1000 &classnamelen) == ERROR_SUCCESS)
1001 {
1002 classnamelen /= sizeof(WCHAR);
1003 if (classnamelen == ARRAY_SIZE(classname))
1004 classnamelen--;
1005
1006 classname[classnamelen] = '\0';
1007 TRACE("File type: %s\n", debugstr_w(classname));
1008 }
1009 else
1010 {
1011 *classname = '\0';
1012 }
1013 }
1014
1015 if (*classname)
1016 {
1017 /* pass the verb string to SHELL_FindExecutableByVerb() */
1019
1020 if (retval > 32)
1021 {
1022 DWORD finishedLen;
1023 SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen, lpPath);
1024 if (finishedLen > resultLen)
1025 ERR("Argify buffer not large enough.. truncated\n");
1026 /* Remove double quotation marks and command line arguments */
1027 if (*lpResult == '"')
1028 {
1029 WCHAR *p = lpResult;
1030 while (*(p + 1) != '"')
1031 {
1032 *p = *(p + 1);
1033 p++;
1034 }
1035 *p = '\0';
1036 }
1037 else
1038 {
1039 /* Truncate on first space */
1040 WCHAR *p = lpResult;
1041 while (*p != ' ' && *p != '\0')
1042 p++;
1043 *p = '\0';
1044 }
1045 }
1046 }
1047 else /* Check win.ini */
1048 {
1049 /* Toss the leading dot */
1050 extension++;
1051 if (GetProfileStringW(L"extensions", extension, L"", command, ARRAY_SIZE(command)) > 0)
1052 {
1053 if (wcslen(command) != 0)
1054 {
1055 wcscpy(lpResult, command);
1056 tok = wcschr(lpResult, '^'); /* should be ^.extension? */
1057 if (tok != NULL)
1058 {
1059 tok[0] = '\0';
1060 wcscat(lpResult, xlpFile); /* what if no dir in xlpFile? */
1061 tok = wcschr(command, '^'); /* see above */
1062 if ((tok != NULL) && (wcslen(tok) > 5))
1063 {
1064 wcscat(lpResult, &tok[5]);
1065 }
1066 }
1067 retval = 33; /* FIXME - see above */
1068 }
1069 }
1070 }
1071
1072 TRACE("returning path %s, retval %d\n", debugstr_w(lpResult), retval);
1073 return retval;
1074}
1075
1076/******************************************************************
1077 * dde_cb
1078 *
1079 * callback for the DDE connection. not really useful
1080 */
1081static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv,
1082 HSZ hsz1, HSZ hsz2, HDDEDATA hData,
1083 ULONG_PTR dwData1, ULONG_PTR dwData2)
1084{
1085 TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
1086 uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
1087 return NULL;
1088}
1089
1090/******************************************************************
1091 * dde_connect
1092 *
1093 * ShellExecute helper. Used to do an operation with a DDE connection
1094 *
1095 * Handles both the direct connection (try #1), and if it fails,
1096 * launching an application and trying (#2) to connect to it
1097 *
1098 */
1099static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec,
1100 const WCHAR* lpFile, WCHAR *env,
1101 LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc,
1102 const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
1103{
1104 WCHAR regkey[256];
1105 WCHAR * endkey = regkey + wcslen(key);
1106 WCHAR app[256], topic[256], ifexec[256], static_res[256];
1108 WCHAR * res;
1109 LONG applen, topiclen, ifexeclen;
1110 WCHAR * exec;
1111 DWORD ddeInst = 0;
1112 DWORD tid;
1113 DWORD resultLen, endkeyLen;
1114 HSZ hszApp, hszTopic;
1115 HCONV hConv;
1116 HDDEDATA hDdeData;
1117 unsigned ret = SE_ERR_NOASSOC;
1118 BOOL unicode = !(GetVersion() & 0x80000000);
1119
1120 if (strlenW(key) + 1 > ARRAY_SIZE(regkey))
1121 {
1122 FIXME("input parameter %s larger than buffer\n", debugstr_w(key));
1123 return 2;
1124 }
1125 wcscpy(regkey, key);
1126 endkeyLen = ARRAY_SIZE(regkey) - (endkey - regkey);
1127 if (strlenW(L"\\application") + 1 > endkeyLen)
1128 {
1129 FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\application"));
1130 return 2;
1131 }
1132 wcscpy(endkey, L"\\application");
1133 applen = sizeof(app);
1134 if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, app, &applen) != ERROR_SUCCESS)
1135 {
1136 WCHAR command[1024], fullpath[MAX_PATH];
1137 LPWSTR ptr = NULL;
1138 DWORD ret = 0;
1139
1140 /* Get application command from start string and find filename of application */
1141 if (*start == '"')
1142 {
1143 if (strlenW(start + 1) + 1 > ARRAY_SIZE(command))
1144 {
1145 FIXME("size of input parameter %s larger than buffer\n",
1146 debugstr_w(start + 1));
1147 return 2;
1148 }
1149 wcscpy(command, start + 1);
1150 if ((ptr = wcschr(command, '"')))
1151 * ptr = 0;
1152 ret = SearchPathW(NULL, command, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr);
1153 }
1154 else
1155 {
1156 LPCWSTR p;
1157 LPWSTR space;
1158 for (p = start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1)
1159 {
1160 int idx = space - start;
1161 memcpy(command, start, idx * sizeof(WCHAR));
1162 command[idx] = '\0';
1163 if ((ret = SearchPathW(NULL, command, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr)))
1164 break;
1165 }
1166 if (!ret)
1167 ret = SearchPathW(NULL, start, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr);
1168 }
1169
1170 if (!ret)
1171 {
1172 ERR("Unable to find application path for command %s\n", debugstr_w(start));
1173 return ERROR_ACCESS_DENIED;
1174 }
1175 if (strlenW(ptr) + 1 > ARRAY_SIZE(app))
1176 {
1177 FIXME("size of found path %s larger than buffer\n", debugstr_w(ptr));
1178 return 2;
1179 }
1180 wcscpy(app, ptr);
1181
1182 /* Remove extensions (including .so) */
1183 ptr = app + wcslen(app) - 3;
1184 if (ptr > app && !wcscmp(ptr, L".so"))
1185 *ptr = 0;
1186
1187 ptr = const_cast<LPWSTR>(strrchrW(app, '.'));
1188 assert(ptr);
1189 *ptr = 0;
1190 }
1191
1192 if (strlenW(L"\\topic") + 1 > endkeyLen)
1193 {
1194 FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\topic"));
1195 return 2;
1196 }
1197 wcscpy(endkey, L"\\topic");
1198 topiclen = sizeof(topic);
1199 if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS)
1200 {
1201 wcscpy(topic, L"System");
1202 }
1203
1204 if (unicode)
1205 {
1207 return 2;
1208 }
1209 else
1210 {
1212 return 2;
1213 }
1214
1217
1218 hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
1219 exec = ddeexec;
1220 if (!hConv)
1221 {
1222 TRACE("Launching %s\n", debugstr_w(start));
1223 ret = execfunc(start, env, TRUE, psei, psei_out);
1224 if (ret <= 32)
1225 {
1226 TRACE("Couldn't launch\n");
1227 goto error;
1228 }
1229 /* if ddeexec is NULL, then we just need to exit here */
1230 if (ddeexec == NULL)
1231 {
1232 TRACE("Exiting because ddeexec is NULL. ret=42.\n");
1233 /* See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew */
1234 /* for reason why we use 42 here and also "Shell32_apitest ShellExecuteW" regression test */
1235 return 42;
1236 }
1237 /* if ddeexec is 'empty string', then we just need to exit here */
1238 if (wcscmp(ddeexec, L"") == 0)
1239 {
1240 TRACE("Exiting because ddeexec is 'empty string'. ret=42.\n");
1241 /* See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew */
1242 /* for reason why we use 42 here and also "Shell32_apitest ShellExecuteW" regression test */
1243 return 42;
1244 }
1245 hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
1246 if (!hConv)
1247 {
1248 TRACE("Couldn't connect. ret=%d\n", ret);
1251 return 30; /* whatever */
1252 }
1253 if (strlenW(L"\\ifexec") + 1 > endkeyLen)
1254 {
1255 FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\ifexec"));
1256 return 2;
1257 }
1258 strcpyW(endkey, L"\\ifexec");
1259 ifexeclen = sizeof(ifexec);
1260 if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS)
1261 {
1262 exec = ifexec;
1263 }
1264 }
1265
1266 SHELL_ArgifyW(static_res, ARRAY_SIZE(static_res), exec, lpFile, pidl, szCommandline, &resultLen, NULL);
1267 if (resultLen > ARRAY_SIZE(static_res))
1268 {
1269 dynamic_res.Allocate(resultLen);
1270 res = dynamic_res;
1271 SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL, NULL);
1272 }
1273 else
1274 res = static_res;
1275 TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res));
1276
1277 /* It's documented in the KB 330337 that IE has a bug and returns
1278 * error DMLERR_NOTPROCESSED on XTYP_EXECUTE request.
1279 */
1280 if (unicode)
1281 hDdeData = DdeClientTransaction((LPBYTE)res, (strlenW(res) + 1) * sizeof(WCHAR), hConv, 0L, 0, XTYP_EXECUTE, 30000, &tid);
1282 else
1283 {
1284 DWORD lenA = WideCharToMultiByte(CP_ACP, 0, res, -1, NULL, 0, NULL, NULL);
1286 resA.Allocate(lenA);
1287 WideCharToMultiByte(CP_ACP, 0, res, -1, resA, lenA, NULL, NULL);
1288 hDdeData = DdeClientTransaction( (LPBYTE)(LPSTR)resA, lenA, hConv, 0L, 0,
1289 XTYP_EXECUTE, 10000, &tid );
1290 }
1291 if (hDdeData)
1292 DdeFreeDataHandle(hDdeData);
1293 else
1294 WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst));
1295 ret = 33;
1296
1297 DdeDisconnect(hConv);
1298
1299error:
1301
1302 return ret;
1303}
1304
1305/*************************************************************************
1306 * execute_from_key [Internal]
1307 */
1309 LPCWSTR szCommandline, LPCWSTR executable_name,
1310 SHELL_ExecuteW32 execfunc,
1312{
1313 WCHAR cmd[256], param[1024], ddeexec[256];
1314 DWORD cmdlen = sizeof(cmd), ddeexeclen = sizeof(ddeexec);
1316 DWORD resultLen;
1317 LPWSTR tmp;
1318
1319 TRACE("%s %s %s %s %s\n", debugstr_w(key), debugstr_w(lpFile), debugstr_w(env),
1320 debugstr_w(szCommandline), debugstr_w(executable_name));
1321
1322 cmd[0] = '\0';
1323 param[0] = '\0';
1324
1325 /* Get the application from the registry */
1327 {
1328 TRACE("got cmd: %s\n", debugstr_w(cmd));
1329
1330 /* Is there a replace() function anywhere? */
1331 cmdlen /= sizeof(WCHAR);
1332 if (cmdlen >= ARRAY_SIZE(cmd))
1333 cmdlen = ARRAY_SIZE(cmd) - 1;
1334 cmd[cmdlen] = '\0';
1335 SHELL_ArgifyW(param, ARRAY_SIZE(param), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen,
1336 (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL);
1337 if (resultLen > ARRAY_SIZE(param))
1338 ERR("Argify buffer not large enough, truncating\n");
1339 }
1340
1341 /* Get the parameters needed by the application
1342 from the associated ddeexec key */
1343 tmp = const_cast<LPWSTR>(strstrW(key, L"command"));
1344 assert(tmp);
1345 wcscpy(tmp, L"ddeexec");
1346
1347 if (RegQueryValueW(HKEY_CLASSES_ROOT, key, ddeexec, (LONG *)&ddeexeclen) == ERROR_SUCCESS)
1348 {
1349 TRACE("Got ddeexec %s => %s\n", debugstr_w(key), debugstr_w(ddeexec));
1350 if (!param[0]) strcpyW(param, executable_name);
1351 retval = dde_connect(key, param, ddeexec, lpFile, env, szCommandline, (LPITEMIDLIST)psei->lpIDList, execfunc, psei, psei_out);
1352 }
1353 else if (param[0])
1354 {
1355 TRACE("executing: %s\n", debugstr_w(param));
1356 retval = execfunc(param, env, FALSE, psei, psei_out);
1357 }
1358 else
1359 WARN("Nothing appropriate found for %s\n", debugstr_w(key));
1360
1361 return retval;
1362}
1363
1364/*************************************************************************
1365 * FindExecutableA [SHELL32.@]
1366 */
1368{
1370 WCHAR *wFile = NULL, *wDirectory = NULL;
1371 WCHAR wResult[MAX_PATH];
1372
1373 if (lpFile) __SHCloneStrAtoW(&wFile, lpFile);
1374 if (lpDirectory) __SHCloneStrAtoW(&wDirectory, lpDirectory);
1375
1376 retval = FindExecutableW(wFile, wDirectory, wResult);
1377 WideCharToMultiByte(CP_ACP, 0, wResult, -1, lpResult, MAX_PATH, NULL, NULL);
1378 SHFree(wFile);
1379 SHFree(wDirectory);
1380
1381 TRACE("returning %s\n", lpResult);
1382 return retval;
1383}
1384
1385/*************************************************************************
1386 * FindExecutableW [SHELL32.@]
1387 *
1388 * This function returns the executable associated with the specified file
1389 * for the default verb.
1390 *
1391 * PARAMS
1392 * lpFile [I] The file to find the association for. This must refer to
1393 * an existing file otherwise FindExecutable fails and returns
1394 * SE_ERR_FNF.
1395 * lpResult [O] Points to a buffer into which the executable path is
1396 * copied. This parameter must not be NULL otherwise
1397 * FindExecutable() segfaults. The buffer must be of size at
1398 * least MAX_PATH characters.
1399 *
1400 * RETURNS
1401 * A value greater than 32 on success, less than or equal to 32 otherwise.
1402 * See the SE_ERR_* constants.
1403 *
1404 * NOTES
1405 * On Windows XP and 2003, FindExecutable() seems to first convert the
1406 * filename into 8.3 format, thus taking into account only the first three
1407 * characters of the extension, and expects to find an association for those.
1408 * However other Windows versions behave sanely.
1409 */
1411{
1413 WCHAR old_dir[MAX_PATH], res[MAX_PATH];
1414 DWORD cch = _countof(res);
1415 LPCWSTR dirs[2];
1416
1417 TRACE("File %s, Dir %s\n", debugstr_w(lpFile), debugstr_w(lpDirectory));
1418
1419 *lpResult = UNICODE_NULL;
1420
1421 GetCurrentDirectoryW(_countof(old_dir), old_dir);
1422
1423 if (lpDirectory && *lpDirectory)
1424 {
1426 dirs[0] = lpDirectory;
1427 }
1428 else
1429 {
1430 dirs[0] = old_dir;
1431 }
1432 dirs[1] = NULL;
1433
1434 if (!GetShortPathNameW(lpFile, res, _countof(res)))
1435 StringCchCopyW(res, _countof(res), lpFile);
1436
1438 {
1439 // NOTE: The last parameter of this AssocQueryStringW call is "strange" in Windows.
1440 if (PathIsExeW(res) ||
1442 {
1443 StringCchCopyW(lpResult, MAX_PATH, res);
1444 retval = 42;
1445 }
1446 else
1447 {
1449 }
1450 }
1451 else
1452 {
1454 }
1455
1456 TRACE("returning %s\n", debugstr_w(lpResult));
1457 SetCurrentDirectoryW(old_dir);
1458 return (HINSTANCE)retval;
1459}
1460
1461/* FIXME: is this already implemented somewhere else? */
1463{
1465 return sei->hkeyClass;
1466
1467 HKEY hKey = NULL;
1468 if (sei->fMask & SEE_MASK_CLASSNAME)
1469 {
1470 TRACE("class = %s\n", debugstr_w(sei->lpClass));
1472 return hKey;
1473 }
1475 TRACE("ext = %s\n", debugstr_w(ext));
1476 if (!StrIsNullOrEmpty(ext) && SUCCEEDED(HCR_GetProgIdKeyOfExtension(ext, &hKey, FALSE)))
1477 return hKey;
1478 return NULL;
1479}
1480
1482{
1483 CComHeapPtr<ITEMIDLIST> allocatedPidl;
1484 LPITEMIDLIST pidl = NULL;
1485
1486 if (sei->fMask & SEE_MASK_CLASSALL) // FIXME: This makes no sense? SEE_MASK_IDLIST?
1487 {
1488 pidl = (LPITEMIDLIST)sei->lpIDList;
1489 }
1490 else
1491 {
1492 WCHAR fullpath[MAX_PATH];
1493 BOOL ret;
1494
1495 fullpath[0] = 0;
1496 ret = GetFullPathNameW(sei->lpFile, MAX_PATH, fullpath, NULL);
1497 if (!ret)
1499
1500 pidl = ILCreateFromPathW(fullpath);
1501 allocatedPidl.Attach(pidl);
1502 }
1504}
1505
1508{
1510 CMINVOKECOMMANDINFOEX ici;
1512 WCHAR string[0x80];
1513 INT i, n, def = -1;
1514 HMENU hmenu = 0;
1515 HRESULT r;
1516
1517 TRACE("%p %p\n", obj, sei);
1518
1519 r = obj->QueryInterface(IID_PPV_ARG(IContextMenu, &cm));
1520 if (FAILED(r))
1521 return r;
1522
1523 hmenu = CreateMenu();
1524 if (!hmenu)
1525 goto end;
1526
1527 /* the number of the last menu added is returned in r */
1528 r = cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
1529 if (FAILED(r))
1530 goto end;
1531
1533 for (i = 0; i < n; i++)
1534 {
1535 memset(&info, 0, sizeof(info));
1536 info.cbSize = sizeof info;
1538 info.dwTypeData = string;
1539 info.cch = sizeof string;
1540 string[0] = 0;
1542
1543 TRACE("menu %d %s %08x %08lx %08x %08x\n", i, debugstr_w(string),
1544 info.fState, info.dwItemData, info.fType, info.wID);
1545 if ((!sei->lpVerb && (info.fState & MFS_DEFAULT)) ||
1546 (sei->lpVerb && !lstrcmpiW(sei->lpVerb, string)))
1547 {
1548 def = i;
1549 break;
1550 }
1551 }
1552
1553 r = E_FAIL;
1554 if (def == -1)
1555 goto end;
1556
1557 memset(&ici, 0, sizeof ici);
1558 ici.cbSize = sizeof ici;
1559 ici.fMask = (sei->fMask & SEE_CMIC_COMMON_BASICFLAGS) | CMIC_MASK_UNICODE;
1560 ici.nShow = sei->nShow;
1561 ici.lpVerb = MAKEINTRESOURCEA(def);
1562 ici.hwnd = sei->hwnd;
1563 ici.lpParametersW = sei->lpParameters;
1564
1565 r = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
1566
1567 TRACE("invoke command returned %08x\n", r);
1568
1569end:
1570 if (hmenu)
1571 DestroyMenu( hmenu );
1572 return r;
1573}
1574
1576{
1577 TRACE("%p %s %p\n", hkey, debugstr_guid(guid), sei);
1578
1579 CCoInit coInit;
1580
1581 if (FAILED_UNEXPECTEDLY(coInit.hr))
1582 return coInit.hr;
1583
1585 HRESULT hr = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER,
1588 return hr;
1589
1590 CComPtr<IDataObject> dataobj;
1591 hr = shellex_get_dataobj(sei, dataobj);
1593 return hr;
1594
1595 hr = obj->Initialize(NULL, dataobj, hkey);
1597 return hr;
1598
1600 hr = obj->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows));
1602 return hr;
1603
1604 ows->SetSite(NULL);
1605
1607}
1608
1610{
1611 CComHeapPtr<ITEMIDLIST> allocatedPidl;
1612 LPITEMIDLIST pidl = NULL;
1613
1614 if (sei->lpIDList)
1615 {
1616 pidl = (LPITEMIDLIST)sei->lpIDList;
1617 }
1618 else
1619 {
1620 SFGAOF sfga = 0;
1621 HRESULT hr = SHParseDisplayName(sei->lpFile, NULL, &allocatedPidl, SFGAO_STORAGECAPMASK, &sfga);
1622 if (FAILED(hr))
1623 {
1624 WCHAR Buffer[MAX_PATH] = {};
1625 // FIXME: MAX_PATH.....
1627 if (retval <= 32)
1628 return HRESULT_FROM_WIN32(retval);
1629
1630 hr = SHParseDisplayName(Buffer, NULL, &allocatedPidl, SFGAO_STORAGECAPMASK, &sfga);
1631 // This should not happen, we found it...
1633 return hr;
1634 }
1635
1636 pidl = allocatedPidl;
1637 }
1638
1640 LPCITEMIDLIST pidllast = NULL;
1641 HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast);
1642 if (FAILED(hr))
1643 return hr;
1644
1645 return shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IContextMenu, &cm));
1646}
1647
1649{
1650 TRACE("%p\n", sei);
1651
1652 CCoInit coInit;
1653
1654 if (FAILED_UNEXPECTEDLY(coInit.hr))
1655 return coInit.hr;
1656
1660 return hr;
1661
1662 CComHeapPtr<char> verb, parameters, dir;
1663 __SHCloneStrWtoA(&verb, sei->lpVerb);
1664 __SHCloneStrWtoA(&parameters, sei->lpParameters);
1666
1667 BOOL fDefault = StrIsNullOrEmpty(sei->lpVerb);
1668 CMINVOKECOMMANDINFOEX ici = { sizeof(ici) };
1669 ici.fMask = SeeFlagsToCmicFlags(sei->fMask) | CMIC_MASK_UNICODE;
1670 ici.nShow = sei->nShow;
1671 if (!fDefault)
1672 {
1673 ici.lpVerb = verb;
1674 ici.lpVerbW = sei->lpVerb;
1675 }
1676 ici.hwnd = sei->hwnd;
1677 ici.lpParameters = parameters;
1678 ici.lpParametersW = sei->lpParameters;
1679 ici.lpDirectory = dir;
1680 ici.lpDirectoryW = sei->lpDirectory;
1681 ici.dwHotKey = sei->dwHotKey;
1682 ici.hIcon = sei->hIcon;
1683 if (ici.fMask & (CMIC_MASK_HASLINKNAME | CMIC_MASK_HASTITLE))
1684 ici.lpTitleW = sei->lpClass;
1685
1686 enum { idFirst = 1, idLast = 0x7fff };
1687 HMENU hMenu = CreatePopupMenu();
1688 // Note: Windows does not pass CMF_EXTENDEDVERBS so "hidden" verbs cannot be executed
1689 hr = cm->QueryContextMenu(hMenu, 0, idFirst, idLast, fDefault ? CMF_DEFAULTONLY : 0);
1690 if (!FAILED_UNEXPECTEDLY(hr))
1691 {
1692 if (fDefault)
1693 {
1694 INT uDefault = GetMenuDefaultItem(hMenu, FALSE, 0);
1695 uDefault = (uDefault != -1) ? uDefault - idFirst : 0;
1696 ici.lpVerb = MAKEINTRESOURCEA(uDefault);
1697 ici.lpVerbW = MAKEINTRESOURCEW(uDefault);
1698 }
1699
1700 hr = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
1701 if (!FAILED_UNEXPECTEDLY(hr))
1702 hr = S_OK;
1703 }
1704
1705 DestroyMenu(hMenu);
1706
1707 return hr;
1708}
1709
1710
1711/*************************************************************************
1712 * ShellExecute_FromContextMenu [Internal]
1713 */
1715{
1716 HKEY hkey, hkeycm = 0;
1717 WCHAR szguid[39];
1718 HRESULT hr;
1719 GUID guid;
1720 DWORD i;
1721 LONG r;
1722
1723 TRACE("%s\n", debugstr_w(sei->lpFile));
1724
1725 hkey = ShellExecute_GetClassKey(sei);
1726 if (!hkey)
1727 return ERROR_FUNCTION_FAILED;
1728
1729 // FIXME: Words cannot describe how broken this is, all of it needs to die
1730 r = RegOpenKeyW(hkey, L"shellex\\ContextMenuHandlers", &hkeycm);
1731 if (r == ERROR_SUCCESS)
1732 {
1733 i = 0;
1734 while (1)
1735 {
1736 r = RegEnumKeyW(hkeycm, i++, szguid, ARRAY_SIZE(szguid));
1737 if (r != ERROR_SUCCESS)
1738 break;
1739
1740 hr = CLSIDFromString(szguid, &guid);
1741 if (SUCCEEDED(hr))
1742 {
1743 /* stop at the first one that succeeds in running */
1744 hr = shellex_load_object_and_run(hkey, &guid, sei);
1745 if (SUCCEEDED(hr))
1746 break;
1747 }
1748 }
1749 RegCloseKey(hkeycm);
1750 }
1751
1752 if (hkey != sei->hkeyClass)
1753 RegCloseKey(hkey);
1754 return r;
1755}
1756
1757static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc);
1758
1760{
1761 WCHAR execCmd[1024], classname[1024];
1762 /* launch a document by fileclass like 'WordPad.Document.1' */
1763 /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
1764 /* FIXME: wcmd should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */
1765 ULONG cmask = (psei->fMask & SEE_MASK_CLASSALL);
1766 DWORD resultLen;
1767 BOOL done;
1768 UINT_PTR rslt;
1769
1770 /* FIXME: remove following block when SHELL_quote_and_execute supports hkeyClass parameter */
1771 if (cmask != SEE_MASK_CLASSNAME)
1772 {
1773 WCHAR wcmd[1024];
1775 (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL,
1776 psei->lpVerb,
1777 execCmd, sizeof(execCmd));
1778
1779 /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
1780 TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
1781
1782 wcmd[0] = '\0';
1783 done = SHELL_ArgifyW(wcmd, ARRAY_SIZE(wcmd), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, psei->lpParameters,
1784 &resultLen, (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL);
1785 if (!done && wszApplicationName[0])
1786 {
1787#if 0 // Given HKCR\.test=SZ:"test" and HKCR\test\shell\open\command=SZ:"cmd.exe /K echo.Hello", no filename is
1788 // appended on Windows when there is no %1 nor %L when executed with: shlextdbg.exe /shellexec=c:\file.test /INVOKE
1789 strcatW(wcmd, L" ");
1790 if (*wszApplicationName != '"')
1791 {
1792 strcatW(wcmd, L"\"");
1793 strcatW(wcmd, wszApplicationName);
1794 strcatW(wcmd, L"\"");
1795 }
1796 else
1797 strcatW(wcmd, wszApplicationName);
1798#endif
1799 }
1800 if (resultLen > ARRAY_SIZE(wcmd))
1801 ERR("Argify buffer not large enough... truncating\n");
1802 return execfunc(wcmd, NULL, FALSE, psei, psei_out);
1803 }
1804
1805 strcpyW(classname, psei->lpClass);
1806 rslt = SHELL_FindExecutableByVerb(psei->lpVerb, NULL, classname, execCmd, sizeof(execCmd));
1807
1808 TRACE("SHELL_FindExecutableByVerb returned %u (%s, %s)\n", (unsigned int)rslt, debugstr_w(classname), debugstr_w(execCmd));
1809 if (33 > rslt)
1810 return rslt;
1811 rslt = SHELL_quote_and_execute( execCmd, L"", classname,
1812 wszApplicationName, NULL, psei,
1813 psei_out, execfunc );
1814 return rslt;
1815
1816}
1817
1818static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen)
1819{
1821 BOOL appKnownSingular = FALSE;
1822
1823 /* last chance to translate IDList: now also allow CLSID paths */
1825 if (buffer[0] == ':' && buffer[1] == ':') {
1826 /* open shell folder for the specified class GUID */
1827 if (strlenW(buffer) + 1 > parametersLen)
1828 ERR("parameters len exceeds buffer size (%i > %i), truncating\n",
1829 lstrlenW(buffer) + 1, parametersLen);
1830 lstrcpynW(wszParameters, buffer, parametersLen);
1831 if (strlenW(L"explorer.exe") > dwApplicationNameLen)
1832 ERR("application len exceeds buffer size (%i), truncating\n",
1833 dwApplicationNameLen);
1834 lstrcpynW(wszApplicationName, L"explorer.exe", dwApplicationNameLen);
1835 appKnownSingular = TRUE;
1836
1837 sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
1838 } else {
1840 DWORD attribs;
1841 DWORD resultLen;
1842 /* Check if we're executing a directory and if so use the
1843 handler for the Folder class */
1848 HCR_GetExecuteCommandW(0, L"Folder",
1849 sei->lpVerb,
1850 buffer, sizeof(buffer))) {
1851 SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
1852 buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen,
1853 !StrIsNullOrEmpty(sei->lpDirectory) ? sei->lpDirectory : NULL);
1854 if (resultLen > dwApplicationNameLen)
1855 ERR("Argify buffer not large enough... truncating\n"); // FIXME: Report this to the caller?
1856 appKnownSingular = FALSE;
1857 // HACKFIX: We really want the !appKnownSingular code in SHELL_execute to split the
1858 // parameters for us but we cannot guarantee that the exe in the registry is quoted.
1859 // We have now turned 'explorer.exe "%1" into 'explorer.exe "c:\path\from\pidl"' and
1860 // need to split to application and parameters.
1861 LPCWSTR params = PathGetArgsW(wszApplicationName);
1862 lstrcpynW(wszParameters, params, parametersLen);
1863 PathRemoveArgsW(wszApplicationName);
1864 PathUnquoteSpacesW(wszApplicationName);
1865 appKnownSingular = TRUE;
1866 }
1867 sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
1868 }
1869 }
1870 return appKnownSingular;
1871}
1872
1873static BOOL
1876 _In_ LPCITEMIDLIST pidl)
1877{
1878 // Bind pidl
1879 CComPtr<IShellFolder> psfFolder;
1880 LPCITEMIDLIST pidlLast;
1881 HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psfFolder), &pidlLast);
1883 return FALSE;
1884
1885 // Get the context menu to invoke a command
1887 hr = psfFolder->GetUIObjectOf(NULL, 1, &pidlLast, IID_NULL_PPV_ARG(IContextMenu, &pCM));
1889 return FALSE;
1890
1891 // Invoke a command
1892 CMINVOKECOMMANDINFO ici = { sizeof(ici) };
1893 ici.fMask = (sei->fMask & SEE_CMIC_COMMON_BASICFLAGS) & ~CMIC_MASK_UNICODE; // FIXME: Unicode?
1894 ici.nShow = sei->nShow;
1895 ici.hwnd = sei->hwnd;
1896 char szVerb[VERBKEY_CCHMAX];
1897 if (sei->lpVerb && sei->lpVerb[0])
1898 {
1899 WideCharToMultiByte(CP_ACP, 0, sei->lpVerb, -1, szVerb, _countof(szVerb), NULL, NULL);
1900 szVerb[_countof(szVerb) - 1] = ANSI_NULL; // Avoid buffer overrun
1901 ici.lpVerb = szVerb;
1902 }
1903 else // The default verb?
1904 {
1905 HMENU hMenu = CreatePopupMenu();
1906 const INT idCmdFirst = 1, idCmdLast = 0x7FFF;
1907 hr = pCM->QueryContextMenu(hMenu, 0, idCmdFirst, idCmdLast, CMF_DEFAULTONLY);
1909 {
1910 DestroyMenu(hMenu);
1911 return FALSE;
1912 }
1913
1914 INT nDefaultID = GetMenuDefaultItem(hMenu, FALSE, 0);
1915 DestroyMenu(hMenu);
1916 if (nDefaultID == -1)
1917 nDefaultID = idCmdFirst;
1918
1919 ici.lpVerb = MAKEINTRESOURCEA(nDefaultID - idCmdFirst);
1920 }
1921 hr = pCM->InvokeCommand(&ici);
1922
1923 return !FAILED_UNEXPECTEDLY(hr);
1924}
1925
1926static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
1927{
1929 DWORD len;
1931
1932 /* Length of quotes plus length of command plus NULL terminator */
1933 len = 2 + lstrlenW(wcmd) + 1;
1934 if (wszParameters[0])
1935 {
1936 /* Length of space plus length of parameters */
1937 len += 1 + lstrlenW(wszParameters);
1938 }
1939 wszQuotedCmd.Allocate(len);
1940 /* Must quote to handle case where cmd contains spaces,
1941 * else security hole if malicious user creates executable file "C:\\Program"
1942 */
1943 strcpyW(wszQuotedCmd, L"\"");
1944 strcatW(wszQuotedCmd, wcmd);
1945 strcatW(wszQuotedCmd, L"\"");
1946 if (wszParameters[0])
1947 {
1948 strcatW(wszQuotedCmd, L" ");
1949 strcatW(wszQuotedCmd, wszParameters);
1950 }
1951
1952 TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(wszKeyname));
1953
1954 if (*wszKeyname)
1955 retval = execute_from_key(wszKeyname, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
1956 else
1957 retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out);
1958
1959 return retval;
1960}
1961
1963{
1966 LPCWSTR lpstrRes;
1967 INT iSize;
1968 DWORD len;
1969
1970 lpstrRes = strchrW(lpFile, ':');
1971 if (lpstrRes)
1972 iSize = lpstrRes - lpFile;
1973 else
1974 iSize = strlenW(lpFile);
1975
1976 TRACE("Got URL: %s\n", debugstr_w(lpFile));
1977 /* Looking for ...<protocol>\shell<lpVerb>\command */
1978 len = iSize + lstrlenW(L"\\shell\\") + lstrlenW(L"\\command") + 1;
1979 if (psei->lpVerb && *psei->lpVerb)
1980 len += lstrlenW(psei->lpVerb);
1981 else
1982 len += lstrlenW(L"open"); // FIXME: Use HCR_GetExecuteCommandW or AssocAPI
1983 lpstrProtocol.Allocate(len);
1984 memcpy(lpstrProtocol, lpFile, iSize * sizeof(WCHAR));
1985 lpstrProtocol[iSize] = '\0';
1986 strcatW(lpstrProtocol, L"\\shell\\");
1987 strcatW(lpstrProtocol, psei->lpVerb && *psei->lpVerb ? psei->lpVerb : L"open");
1988 strcatW(lpstrProtocol, L"\\command");
1989
1990 retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters,
1991 wcmd, execfunc, psei, psei_out);
1992
1993 return retval;
1994}
1995
1997{
1998 WCHAR msg[2048];
1999 DWORD_PTR msgArguments[3] = { (DWORD_PTR)filename, 0, 0 };
2000 const DWORD error_code = GetLastError();
2001
2002 if (retval == SE_ERR_NOASSOC)
2004 else
2006 NULL,
2007 error_code,
2009 msg,
2010 ARRAY_SIZE(msg),
2011 (va_list*)msgArguments);
2012
2014 SetLastError(error_code); // Restore
2015}
2016
2018{
2020 DWORD len;
2021
2023 if (!len) return NULL;
2024
2025 if (!buf.Allocate(len))
2026 return NULL;
2027
2029 if (!len)
2030 return NULL;
2031
2032 return buf.Detach();
2033}
2034
2035/*************************************************************************
2036 * SHELL_execute [Internal]
2037 */
2039{
2040 static const DWORD unsupportedFlags =
2042
2043 DWORD len;
2045 BOOL appKnownSingular = FALSE;
2046
2047 /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */
2048 sei->hProcess = NULL;
2049 SHELLEXECUTEINFOW sei_tmp = *sei;
2050
2051 TRACE("mask=0x%08x hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n",
2052 sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb),
2053 debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters),
2054 debugstr_w(sei_tmp.lpDirectory), sei_tmp.nShow,
2055 ((sei_tmp.fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME) ?
2056 debugstr_w(sei_tmp.lpClass) : "not used");
2057
2058 // Call hooks before expanding and resolving strings
2060 if (hr != S_FALSE)
2061 {
2062 int err = Win32ErrFromHInst(sei->hInstApp);
2063 if (err <= 0)
2064 {
2065 sei->hInstApp = (HINSTANCE)UlongToHandle(42);
2066 return TRUE;
2067 }
2069 return FALSE;
2070 }
2071
2072 /* make copies of all path/command strings */
2073 CHeapPtr<WCHAR, CLocalAllocator> wszApplicationName;
2074 DWORD dwApplicationNameLen = MAX_PATH + 2;
2075 if (!sei_tmp.lpFile)
2076 {
2077 wszApplicationName.Allocate(dwApplicationNameLen);
2078 *wszApplicationName = '\0';
2079 }
2080 else if (*sei_tmp.lpFile == '\"' && sei_tmp.lpFile[(len = strlenW(sei_tmp.lpFile))-1] == '\"')
2081 {
2082 if(len-1 >= dwApplicationNameLen)
2083 dwApplicationNameLen = len;
2084
2085 wszApplicationName.Allocate(dwApplicationNameLen);
2086 memcpy(wszApplicationName, sei_tmp.lpFile + 1, len * sizeof(WCHAR));
2087
2088 if(len > 2)
2089 wszApplicationName[len-2] = '\0';
2090 appKnownSingular = TRUE;
2091
2092 TRACE("wszApplicationName=%s\n", debugstr_w(wszApplicationName));
2093 }
2094 else
2095 {
2096 DWORD l = strlenW(sei_tmp.lpFile) + 1;
2097 if(l > dwApplicationNameLen) dwApplicationNameLen = l + 1;
2098 wszApplicationName.Allocate(dwApplicationNameLen);
2099 memcpy(wszApplicationName, sei_tmp.lpFile, l * sizeof(WCHAR));
2100
2101 if (wszApplicationName[2] == 0 && wszApplicationName[1] == L':' &&
2102 ((L'A' <= wszApplicationName[0] && wszApplicationName[0] <= L'Z') ||
2103 (L'a' <= wszApplicationName[0] && wszApplicationName[0] <= L'z')))
2104 {
2105 // 'C:' --> 'C:\'
2106 PathAddBackslashW(wszApplicationName);
2107 }
2108 }
2109
2110 WCHAR parametersBuffer[1024];
2111 LPWSTR wszParameters = parametersBuffer;
2113 DWORD parametersLen = _countof(parametersBuffer);
2114
2115 if (sei_tmp.lpParameters)
2116 {
2117 len = lstrlenW(sei_tmp.lpParameters) + 1;
2118 if (len > parametersLen)
2119 {
2120 wszParamAlloc.Allocate(len);
2121 wszParameters = wszParamAlloc;
2122 parametersLen = len;
2123 }
2124 strcpyW(wszParameters, sei_tmp.lpParameters);
2125 }
2126 else
2127 *wszParameters = L'\0';
2128
2129 // Get the working directory
2130 WCHAR dirBuffer[MAX_PATH];
2131 LPWSTR wszDir = dirBuffer;
2132 wszDir[0] = UNICODE_NULL;
2134 if (sei_tmp.lpDirectory && *sei_tmp.lpDirectory)
2135 {
2136 if (sei_tmp.fMask & SEE_MASK_DOENVSUBST)
2137 {
2138 LPWSTR tmp = expand_environment(sei_tmp.lpDirectory);
2139 if (tmp)
2140 {
2141 wszDirAlloc.Attach(tmp);
2142 wszDir = wszDirAlloc;
2143 }
2144 }
2145 else
2146 {
2147 __SHCloneStrW(&wszDirAlloc, sei_tmp.lpDirectory);
2148 if (wszDirAlloc)
2149 wszDir = wszDirAlloc;
2150 }
2151 }
2152 if (!wszDir[0])
2153 {
2154 ::GetCurrentDirectoryW(_countof(dirBuffer), dirBuffer);
2155 wszDir = dirBuffer;
2156 }
2157 // NOTE: ShellExecute should accept the invalid working directory for historical reason.
2158 if (!PathIsDirectoryW(wszDir))
2159 {
2160 INT iDrive = PathGetDriveNumberW(wszDir);
2161 if (iDrive >= 0)
2162 {
2163 PathStripToRootW(wszDir);
2164 if (!PathIsDirectoryW(wszDir))
2165 {
2166 ::GetWindowsDirectoryW(dirBuffer, _countof(dirBuffer));
2167 wszDir = dirBuffer;
2168 }
2169 }
2170 }
2171
2172 /* adjust string pointers to point to the new buffers */
2173 sei_tmp.lpFile = wszApplicationName;
2174 sei_tmp.lpParameters = wszParameters;
2175 sei_tmp.lpDirectory = wszDir;
2176
2177 if (sei_tmp.fMask & unsupportedFlags)
2178 {
2179 FIXME("flags ignored: 0x%08x\n", sei_tmp.fMask & unsupportedFlags);
2180 }
2181
2182 /* process the IDList */
2183 if (sei_tmp.fMask & SEE_MASK_IDLIST &&
2185 {
2186 LPCITEMIDLIST pidl = (LPCITEMIDLIST)sei_tmp.lpIDList;
2187 hr = SHGetNameAndFlagsW(pidl, SHGDN_FORPARSING, wszApplicationName, dwApplicationNameLen, NULL);
2188 if (FAILED(hr))
2189 {
2190 if (dwApplicationNameLen)
2191 *wszApplicationName = UNICODE_NULL;
2192 if (!_ILIsDesktop(pidl))
2193 TRACE("Unable to get PIDL parsing path\n");
2194 }
2195 appKnownSingular = TRUE;
2196 TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName));
2197 }
2198
2199 if ((sei_tmp.fMask & SEE_MASK_DOENVSUBST) && !StrIsNullOrEmpty(sei_tmp.lpFile))
2200 {
2201 WCHAR *tmp = expand_environment(sei_tmp.lpFile);
2202 if (tmp)
2203 {
2204 wszApplicationName.Attach(tmp);
2205 sei_tmp.lpFile = wszApplicationName;
2206 }
2207 }
2208
2210 {
2211 hr = ShellExecute_ContextMenuVerb(&sei_tmp);
2212 if (SUCCEEDED(hr))
2213 {
2214 sei->hInstApp = (HINSTANCE)42;
2215 return TRUE;
2216 }
2217 }
2218
2220 {
2221 sei->hInstApp = (HINSTANCE) 33;
2222 return TRUE;
2223 }
2224
2225 if (sei_tmp.fMask & SEE_MASK_CLASSALL)
2226 {
2227 retval = SHELL_execute_class(wszApplicationName, &sei_tmp, sei, execfunc);
2228 if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
2229 {
2231
2232 //FIXME
2233 // need full path
2234
2235 Info.pcszFile = wszApplicationName;
2236 Info.pcszClass = NULL;
2237 Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
2238
2239 //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
2241 do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
2242 }
2243 return retval > 32;
2244 }
2245
2246 if (!(sei_tmp.fMask & SEE_MASK_IDLIST) && // Not an ID List
2247 (StrCmpNIW(sei_tmp.lpFile, L"shell:", 6) == 0 ||
2248 StrCmpNW(sei_tmp.lpFile, L"::{", 3) == 0))
2249 {
2250 CComHeapPtr<ITEMIDLIST> pidlParsed;
2251 hr = SHParseDisplayName(sei_tmp.lpFile, NULL, &pidlParsed, 0, NULL);
2252 if (SUCCEEDED(hr) && SHELL_InvokePidl(&sei_tmp, pidlParsed))
2253 {
2254 sei_tmp.hInstApp = (HINSTANCE)UlongToHandle(42);
2255 return TRUE;
2256 }
2257 }
2258
2259 /* Has the IDList not yet been translated? */
2260 if (sei_tmp.fMask & SEE_MASK_IDLIST)
2261 {
2262 appKnownSingular = SHELL_translate_idlist( &sei_tmp, wszParameters,
2263 parametersLen,
2264 wszApplicationName,
2265 dwApplicationNameLen );
2266 }
2267
2268 /* convert file URLs */
2269 if (UrlIsFileUrlW(sei_tmp.lpFile))
2270 {
2273 if (!buf.Allocate(size) || FAILED(PathCreateFromUrlW(sei_tmp.lpFile, buf, &size, 0)))
2274 {
2276 return FALSE;
2277 }
2278
2279 wszApplicationName.Attach(buf.Detach());
2280 sei_tmp.lpFile = wszApplicationName;
2281 }
2282
2283 /* Else, try to execute the filename */
2284 TRACE("execute: %s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir));
2285
2286 /* separate out command line arguments from executable file name */
2287 LPCWSTR lpFile = sei_tmp.lpFile;
2288 if (!*sei_tmp.lpParameters && !appKnownSingular)
2289 {
2290 /* If the executable path is quoted, handle the rest of the command line as parameters. */
2291 if (sei_tmp.lpFile[0] == L'"')
2292 {
2293 LPWSTR pszArgs = PathGetArgsW(wszApplicationName);
2294 PathRemoveArgsW(wszApplicationName);
2295 PathUnquoteSpacesW(wszApplicationName);
2296 parametersLen = lstrlenW(pszArgs);
2297 if (parametersLen < _countof(parametersBuffer))
2298 {
2299 StringCchCopyW(parametersBuffer, _countof(parametersBuffer), pszArgs);
2300 wszParameters = parametersBuffer;
2301 }
2302 else
2303 {
2304 wszParamAlloc.Attach(StrDupW(pszArgs));
2305 wszParameters = wszParamAlloc;
2306 }
2307 }
2308 /* We have to test sei instead of sei_tmp because sei_tmp had its
2309 * input fMask modified above in SHELL_translate_idlist.
2310 * This code is needed to handle the case where we only have an
2311 * lpIDList with multiple CLSID/PIDL's (not 'My Computer' only) */
2312 else if ((sei->fMask & SEE_MASK_IDLIST) == SEE_MASK_IDLIST)
2313 {
2314 WCHAR buffer[MAX_PATH], xlpFile[MAX_PATH];
2315 LPWSTR space, s;
2316
2317 LPWSTR beg = wszApplicationName;
2318 for(s = beg; (space = const_cast<LPWSTR>(strchrW(s, L' '))); s = space + 1)
2319 {
2320 int idx = space - sei_tmp.lpFile;
2321 memcpy(buffer, sei_tmp.lpFile, idx * sizeof(WCHAR));
2322 buffer[idx] = '\0';
2323
2324 if (SearchPathW(*sei_tmp.lpDirectory ? sei_tmp.lpDirectory : NULL,
2325 buffer, L".exe", _countof(xlpFile), xlpFile, NULL))
2326 {
2327 /* separate out command from parameter string */
2328 LPCWSTR p = space + 1;
2329
2330 while(isspaceW(*p))
2331 ++p;
2332
2333 strcpyW(wszParameters, p);
2334 *space = L'\0';
2335
2336 break;
2337 }
2338 }
2339 }
2340 }
2341
2342 WCHAR wcmdBuffer[1024];
2343 LPWSTR wcmd = wcmdBuffer;
2344 DWORD wcmdLen = _countof(wcmdBuffer);
2346
2347 /* Only execute if it has an executable extension */
2348 if (PathIsExeW(lpFile))
2349 {
2350 len = lstrlenW(wszApplicationName) + 3;
2351 if (sei_tmp.lpParameters[0])
2352 len += 1 + lstrlenW(wszParameters);
2353 if (len > wcmdLen)
2354 {
2355 wcmdAlloc.Allocate(len);
2356 wcmd = wcmdAlloc;
2357 wcmdLen = len;
2358 }
2359 swprintf(wcmd, L"\"%s\"", (LPWSTR)wszApplicationName);
2360 if (sei_tmp.lpParameters[0])
2361 {
2362 strcatW(wcmd, L" ");
2363 strcatW(wcmd, wszParameters);
2364 }
2365
2366 retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei);
2367 if (retval > 32)
2368 return TRUE;
2369 }
2370
2371 /* Else, try to find the executable */
2372 WCHAR wszKeyname[256];
2374 wcmd[0] = UNICODE_NULL;
2375 retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, wszKeyname, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
2376 if (retval > 32) /* Found */
2377 {
2378 retval = SHELL_quote_and_execute(wcmd, wszParameters, wszKeyname,
2379 wszApplicationName, env, &sei_tmp,
2380 sei, execfunc);
2381 }
2382 else if (PathIsDirectoryW(lpFile))
2383 {
2384 WCHAR wExec[MAX_PATH];
2386 if (lpQuotedFile.Allocate(strlenW(lpFile) + 3))
2387 {
2388 retval = SHELL_FindExecutable(sei_tmp.lpDirectory, L"explorer",
2389 L"open", wExec, MAX_PATH,
2390 NULL, &env, NULL, NULL);
2391 if (retval > 32)
2392 {
2393 swprintf(lpQuotedFile, L"\"%s\"", lpFile);
2394 retval = SHELL_quote_and_execute(wExec, lpQuotedFile,
2395 wszKeyname,
2396 wszApplicationName, env,
2397 &sei_tmp, sei, execfunc);
2398 }
2399 }
2400 else
2401 retval = 0; /* Out of memory */
2402 }
2403 else if (PathIsURLW(lpFile)) /* File not found, check for URL */
2404 {
2405 retval = SHELL_execute_url(lpFile, wcmd, &sei_tmp, sei, execfunc );
2406 }
2407 /* Check if file specified is in the form www.??????.*** */
2408 else if (!strncmpiW(lpFile, L"www", 3))
2409 {
2410 /* if so, prefix lpFile with http:// and call ShellExecute */
2411 WCHAR lpstrTmpFile[256];
2412 strcpyW(lpstrTmpFile, L"http://");
2413 strcatW(lpstrTmpFile, lpFile); // FIXME: Possible buffer overflow
2414 // FIXME: This will not correctly return the hProcess to the caller
2415 retval = (UINT_PTR)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0);
2416 }
2417
2418 TRACE("retval %lu\n", retval);
2419
2420 if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
2421 {
2422 if (retval == SE_ERR_NOASSOC && !(sei->fMask & SEE_MASK_CLASSALL))
2423 retval = InvokeOpenWith(sei_tmp.hwnd, *sei);
2424 if (retval <= 32)
2425 do_error_dialog(retval, sei_tmp.hwnd, lpFile);
2426 }
2427
2428 sei->hInstApp = (HINSTANCE)(retval > 32 ? 33 : retval);
2429
2430 return retval > 32;
2431}
2432
2433/*************************************************************************
2434 * ShellExecuteA [SHELL32.290]
2435 */
2437 LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
2438{
2440
2441 TRACE("%p,%s,%s,%s,%s,%d\n",
2442 hWnd, debugstr_a(lpVerb), debugstr_a(lpFile),
2443 debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd);
2444
2445 sei.cbSize = sizeof(sei);
2447 sei.hwnd = hWnd;
2448 sei.lpVerb = lpVerb;
2449 sei.lpFile = lpFile;
2450 sei.lpParameters = lpParameters;
2452 sei.nShow = iShowCmd;
2453 sei.lpIDList = 0;
2454 sei.lpClass = 0;
2455 sei.hkeyClass = 0;
2456 sei.dwHotKey = 0;
2457 sei.hProcess = 0;
2458
2460 sei.fMask |= SEE_MASK_NOASYNC;
2461 ShellExecuteExA(&sei);
2462 return sei.hInstApp;
2463}
2464
2465static DWORD
2467{
2468 // FIXME
2469 if (SHELL_execute(sei, SHELL_ExecuteW))
2470 return ERROR_SUCCESS;
2472#if DBG
2473 if (!err)
2474 DbgPrint("FIXME: Failed with error 0 on '%ls'\n", sei->lpFile);
2475#endif
2476 return err ? err : ERROR_FILE_NOT_FOUND;
2477}
2478
2479static VOID
2481 _In_ const SHELLEXECUTEINFOW *ExecInfo,
2482 _In_opt_ LPCWSTR pszCaption,
2483 _In_ DWORD dwError)
2484{
2485 // FIXME: Show error message
2486}
2487
2488/*************************************************************************
2489 * ShellExecuteExA [SHELL32.292]
2490 */
2491BOOL
2492WINAPI
2495{
2496 SHELLEXECUTEINFOW seiW;
2497 BOOL ret;
2498 WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL, *wClass = NULL;
2499
2500 TRACE("%p\n", sei);
2501
2502 if (sei->cbSize != sizeof(SHELLEXECUTEINFOA))
2503 {
2506 return FALSE;
2507 }
2508
2509 memcpy(&seiW, sei, sizeof(SHELLEXECUTEINFOW));
2510
2511 seiW.cbSize = sizeof(SHELLEXECUTEINFOW);
2512
2513 if (sei->lpVerb)
2514 seiW.lpVerb = __SHCloneStrAtoW(&wVerb, sei->lpVerb);
2515
2516 if (sei->lpFile)
2517 seiW.lpFile = __SHCloneStrAtoW(&wFile, sei->lpFile);
2518
2519 if (sei->lpParameters)
2520 seiW.lpParameters = __SHCloneStrAtoW(&wParameters, sei->lpParameters);
2521
2522 if (sei->lpDirectory)
2523 seiW.lpDirectory = __SHCloneStrAtoW(&wDirectory, sei->lpDirectory);
2524
2525 if ((sei->fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME && sei->lpClass)
2526 seiW.lpClass = __SHCloneStrAtoW(&wClass, sei->lpClass);
2527 else
2528 seiW.lpClass = NULL;
2529
2530 ret = ShellExecuteExW(&seiW);
2531
2532 sei->hInstApp = seiW.hInstApp;
2533
2534 if (sei->fMask & SEE_MASK_NOCLOSEPROCESS)
2535 sei->hProcess = seiW.hProcess;
2536
2537 SHFree(wVerb);
2538 SHFree(wFile);
2539 SHFree(wParameters);
2540 SHFree(wDirectory);
2541 SHFree(wClass);
2542
2543 return ret;
2544}
2545
2546/*************************************************************************
2547 * ShellExecuteExW [SHELL32.293]
2548 */
2549BOOL
2550WINAPI
2553{
2554 HRESULT hrCoInit;
2555 DWORD dwError;
2556 ULONG fOldMask;
2557
2558 if (sei->cbSize != sizeof(SHELLEXECUTEINFOW))
2559 {
2562 return FALSE;
2563 }
2564
2565 hrCoInit = SHCoInitializeAnyApartment();
2566
2567 if (SHRegGetBoolUSValueW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
2568 L"MaximizeApps", FALSE, FALSE))
2569 {
2570 switch (sei->nShow)
2571 {
2572 case SW_SHOW:
2573 case SW_SHOWDEFAULT:
2574 case SW_SHOWNORMAL:
2575 case SW_RESTORE:
2576 sei->nShow = SW_SHOWMAXIMIZED;
2577 break;
2578 default:
2579 break;
2580 }
2581 }
2582
2583 fOldMask = sei->fMask;
2584
2585 if (!(fOldMask & SEE_MASK_NOASYNC) && SHELL_InRunDllProcess())
2587
2588 dwError = ShellExecute_Normal(sei);
2589
2590 if (dwError && dwError != ERROR_DLL_NOT_FOUND && dwError != ERROR_CANCELLED)
2591 ShellExecute_ShowError(sei, NULL, dwError);
2592
2593 sei->fMask = fOldMask;
2594
2595 if (SUCCEEDED(hrCoInit))
2597
2598 if (dwError)
2599 SetLastError(dwError);
2600
2601 return dwError == ERROR_SUCCESS;
2602}
2603
2604/*************************************************************************
2605 * ShellExecuteW [SHELL32.294]
2606 */
2608 LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
2609{
2611
2612 TRACE("\n");
2613 sei.cbSize = sizeof(sei);
2615 sei.hwnd = hwnd;
2616 sei.lpVerb = lpVerb;
2617 sei.lpFile = lpFile;
2618 sei.lpParameters = lpParameters;
2620 sei.nShow = nShowCmd;
2621 sei.lpIDList = 0;
2622 sei.lpClass = 0;
2623 sei.hkeyClass = 0;
2624 sei.dwHotKey = 0;
2625 sei.hProcess = 0;
2626
2628 sei.fMask |= SEE_MASK_NOASYNC;
2629 ShellExecuteExW(&sei);
2630 return sei.hInstApp;
2631}
2632
2633/*************************************************************************
2634 * WOWShellExecute [SHELL32.@]
2635 *
2636 * FIXME: the callback function most likely doesn't work the same way on Windows.
2637 */
2639 LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback)
2640{
2641 SHELLEXECUTEINFOW seiW;
2642 WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL;
2643 HANDLE hProcess = 0;
2644
2645 seiW.lpVerb = lpVerb ? __SHCloneStrAtoW(&wVerb, lpVerb) : NULL;
2646 seiW.lpFile = lpFile ? __SHCloneStrAtoW(&wFile, lpFile) : NULL;
2647 seiW.lpParameters = lpParameters ? __SHCloneStrAtoW(&wParameters, lpParameters) : NULL;
2648 seiW.lpDirectory = lpDirectory ? __SHCloneStrAtoW(&wDirectory, lpDirectory) : NULL;
2649
2650 seiW.cbSize = sizeof(seiW);
2651 seiW.fMask = 0;
2652 seiW.hwnd = hWnd;
2653 seiW.nShow = iShowCmd;
2654 seiW.lpIDList = 0;
2655 seiW.lpClass = 0;
2656 seiW.hkeyClass = 0;
2657 seiW.dwHotKey = 0;
2658 seiW.hProcess = hProcess;
2659
2661
2662 SHFree(wVerb);
2663 SHFree(wFile);
2664 SHFree(wParameters);
2665 SHFree(wDirectory);
2666 return seiW.hInstApp;
2667}
2668
2669/*************************************************************************
2670 * OpenAs_RunDLLW [SHELL32.@]
2671 */
2672EXTERN_C void WINAPI
2674{
2676 TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow);
2678}
2679
2680/*************************************************************************
2681 * OpenAs_RunDLLA [SHELL32.@]
2682 */
2683EXTERN_C void WINAPI
2685{
2686 LPWSTR pszCmdLineW = NULL;
2687 TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow);
2688
2689 if (cmdline)
2690 __SHCloneStrAtoW(&pszCmdLineW, cmdline);
2691 OpenAs_RunDLLW(hwnd, hinst, pszCmdLineW, cmdshow);
2692 SHFree(pszCmdLineW);
2693}
2694
2695/*************************************************************************/
2696
2697static LPCWSTR
2698SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0)
2699{
2700 LPCWSTR pch;
2701 size_t ich = 0;
2702 if (*psz == L'"')
2703 {
2704 // 1st argument is quoted. the string in quotes is quoted 1st argument.
2705 // [pch] --> [pszArg0+ich]
2706 for (pch = psz + 1; *pch && ich + 1 < cchArg0; ++ich, ++pch)
2707 {
2708 if (*pch == L'"' && pch[1] == L'"')
2709 {
2710 // doubled double quotations found!
2711 pszArg0[ich] = L'"';
2712 }
2713 else if (*pch == L'"')
2714 {
2715 // single double quotation found!
2716 ++pch;
2717 break;
2718 }
2719 else
2720 {
2721 // otherwise
2722 pszArg0[ich] = *pch;
2723 }
2724 }
2725 }
2726 else
2727 {
2728 // 1st argument is unquoted. non-space sequence is 1st argument.
2729 // [pch] --> [pszArg0+ich]
2730 for (pch = psz; *pch && !iswspace(*pch) && ich + 1 < cchArg0; ++ich, ++pch)
2731 {
2732 pszArg0[ich] = *pch;
2733 }
2734 }
2735 pszArg0[ich] = 0;
2736
2737 // skip space
2738 while (iswspace(*pch))
2739 ++pch;
2740
2741 return pch;
2742}
2743
2745 HWND hwnd,
2746 LPCWSTR pwszCommand,
2747 LPCWSTR pwszStartDir,
2748 int nShow,
2749 LPVOID pUnused,
2750 DWORD dwSeclFlags)
2751{
2754 LPCWSTR pszVerb = NULL;
2755 WCHAR szFile[MAX_PATH], szFile2[MAX_PATH];
2756 HRESULT hr;
2757 LPCWSTR pchParams;
2758 LPWSTR lpCommand = NULL;
2759
2760 if (pwszCommand == NULL)
2762 1, (ULONG_PTR*)pwszCommand);
2763
2764 __SHCloneStrW(&lpCommand, pwszCommand);
2765 StrTrimW(lpCommand, L" \t");
2766
2767 if (dwSeclFlags & SECL_NO_UI)
2769 if (dwSeclFlags & SECL_LOG_USAGE)
2771 if (dwSeclFlags & SECL_USE_IDLIST)
2773
2774 if (dwSeclFlags & SECL_RUNAS)
2775 {
2776 dwSize = 0;
2777 hr = AssocQueryStringW(ASSOCF_NONE, ASSOCSTR_COMMAND, lpCommand, L"runas", NULL, &dwSize);
2778 if (SUCCEEDED(hr) && dwSize != 0)
2779 {
2780 pszVerb = L"runas";
2781 }
2782 }
2783
2784 if (PathIsURLW(lpCommand) || UrlIsW(lpCommand, URLIS_APPLIABLE))
2785 {
2786 StringCchCopyW(szFile, _countof(szFile), lpCommand);
2787 pchParams = NULL;
2788 }
2789 else
2790 {
2791 PCWSTR apPathList[2];
2792
2793 pchParams = SplitParams(lpCommand, szFile, _countof(szFile));
2794 if (szFile[0] != UNICODE_NULL && szFile[1] == L':' &&
2795 szFile[2] == UNICODE_NULL)
2796 {
2797 PathAddBackslashW(szFile);
2798 }
2799
2800 WCHAR szCurDir[MAX_PATH];
2801 GetCurrentDirectoryW(_countof(szCurDir), szCurDir);
2802 if (pwszStartDir)
2803 {
2804 SetCurrentDirectoryW(pwszStartDir);
2805 }
2806
2807 if ((PathIsRelativeW(szFile) &&
2808 GetFullPathNameW(szFile, _countof(szFile2), szFile2, NULL) &&
2809 PathFileExistsW(szFile2)) ||
2810 SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL))
2811 {
2812 StringCchCopyW(szFile, _countof(szFile), szFile2);
2813 }
2814
2815 apPathList[0] = pwszStartDir;
2816 apPathList[1] = NULL;
2817 PathFindOnPathExW(szFile, apPathList, WHICH_DEFAULT);
2818
2819 if (!(dwSeclFlags & SECL_ALLOW_NONEXE))
2820 {
2821 if (!GetBinaryTypeW(szFile, &dwType))
2822 {
2823 SHFree(lpCommand);
2824
2825 if (!(dwSeclFlags & SECL_NO_UI))
2826 {
2827 WCHAR szText[128 + MAX_PATH], szFormat[128];
2829 StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
2830 MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
2831 }
2832 return CO_E_APPNOTFOUND;
2833 }
2834 }
2835 else
2836 {
2838 {
2839 SHFree(lpCommand);
2840
2841 if (!(dwSeclFlags & SECL_NO_UI))
2842 {
2843 WCHAR szText[128 + MAX_PATH], szFormat[128];
2845 StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
2846 MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
2847 }
2849 }
2850 }
2851 }
2852
2853 ZeroMemory(&info, sizeof(info));
2854 info.cbSize = sizeof(info);
2855 info.fMask = dwFlags;
2856 info.hwnd = hwnd;
2857 info.lpVerb = pszVerb;
2858 info.lpFile = szFile;
2859 info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL;
2860 info.lpDirectory = pwszStartDir;
2861 info.nShow = nShow;
2863 SHFree(lpCommand);
2864 return HRESULT_FROM_WIN32(error);
2865}
2866
2867/*************************************************************************
2868 * RealShellExecuteExA (SHELL32.266)
2869 */
2874 _In_opt_ LPCSTR lpOperation,
2875 _In_opt_ LPCSTR lpFile,
2876 _In_opt_ LPCSTR lpParameters,
2878 _In_opt_ LPSTR lpReturn,
2881 _In_ INT nCmdShow,
2882 _Out_opt_ PHANDLE lphProcess,
2884{
2885 SHELLEXECUTEINFOA ExecInfo;
2886
2887 TRACE("(%p, %s, %s, %s, %s, %p, %s, %p, %u, %p, %lu)\n",
2888 hwnd, debugstr_a(lpOperation), debugstr_a(lpFile), debugstr_a(lpParameters),
2890 lpReserved, nCmdShow, lphProcess, dwFlags);
2891
2892 ZeroMemory(&ExecInfo, sizeof(ExecInfo));
2893 ExecInfo.cbSize = sizeof(ExecInfo);
2895 ExecInfo.hwnd = hwnd;
2896 ExecInfo.lpVerb = lpOperation;
2897 ExecInfo.lpFile = lpFile;
2898 ExecInfo.lpParameters = lpParameters;
2899 ExecInfo.lpDirectory = lpDirectory;
2900 ExecInfo.nShow = (WORD)nCmdShow;
2901
2902 if (lpReserved)
2903 {
2904 ExecInfo.fMask |= SEE_MASK_USE_RESERVED;
2905 ExecInfo.hInstApp = (HINSTANCE)lpReserved;
2906 }
2907
2908 if (lpTitle)
2909 {
2910 ExecInfo.fMask |= SEE_MASK_HASTITLE;
2911 ExecInfo.lpClass = lpTitle;
2912 }
2913
2914 if (dwFlags & 1)
2915 ExecInfo.fMask |= SEE_MASK_FLAG_SEPVDM;
2916
2917 if (dwFlags & 2)
2918 ExecInfo.fMask |= SEE_MASK_NO_CONSOLE;
2919
2920 if (lphProcess == NULL)
2921 {
2922 ShellExecuteExA(&ExecInfo);
2923 }
2924 else
2925 {
2926 ExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS;
2927 ShellExecuteExA(&ExecInfo);
2928 *lphProcess = ExecInfo.hProcess;
2929 }
2930
2931 return ExecInfo.hInstApp;
2932}
2933
2934/*************************************************************************
2935 * RealShellExecuteExW (SHELL32.267)
2936 */
2941 _In_opt_ LPCWSTR lpOperation,
2942 _In_opt_ LPCWSTR lpFile,
2943 _In_opt_ LPCWSTR lpParameters,
2945 _In_opt_ LPWSTR lpReturn,
2948 _In_ INT nCmdShow,
2949 _Out_opt_ PHANDLE lphProcess,
2951{
2952 SHELLEXECUTEINFOW ExecInfo;
2953
2954 TRACE("(%p, %s, %s, %s, %s, %p, %s, %p, %u, %p, %lu)\n",
2955 hwnd, debugstr_w(lpOperation), debugstr_w(lpFile), debugstr_w(lpParameters),
2957 lpReserved, nCmdShow, lphProcess, dwFlags);
2958
2959 ZeroMemory(&ExecInfo, sizeof(ExecInfo));
2960 ExecInfo.cbSize = sizeof(ExecInfo);
2962 ExecInfo.hwnd = hwnd;
2963 ExecInfo.lpVerb = lpOperation;
2964 ExecInfo.lpFile = lpFile;
2965 ExecInfo.lpParameters = lpParameters;
2966 ExecInfo.lpDirectory = lpDirectory;
2967 ExecInfo.nShow = (WORD)nCmdShow;
2968
2969 if (lpReserved)
2970 {
2971 ExecInfo.fMask |= SEE_MASK_USE_RESERVED;
2972 ExecInfo.hInstApp = (HINSTANCE)lpReserved;
2973 }
2974
2975 if (lpTitle)
2976 {
2977 ExecInfo.fMask |= SEE_MASK_HASTITLE;
2978 ExecInfo.lpClass = lpTitle;
2979 }
2980
2981 if (dwFlags & 1)
2982 ExecInfo.fMask |= SEE_MASK_FLAG_SEPVDM;
2983
2984 if (dwFlags & 2)
2985 ExecInfo.fMask |= SEE_MASK_NO_CONSOLE;
2986
2987 if (lphProcess == NULL)
2988 {
2989 ShellExecuteExW(&ExecInfo);
2990 }
2991 else
2992 {
2993 ExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS;
2994 ShellExecuteExW(&ExecInfo);
2995 *lphProcess = ExecInfo.hProcess;
2996 }
2997
2998 return ExecInfo.hInstApp;
2999}
3000
3001/*************************************************************************
3002 * RealShellExecuteA (SHELL32.265)
3003 */
3008 _In_opt_ LPCSTR lpOperation,
3009 _In_opt_ LPCSTR lpFile,
3010 _In_opt_ LPCSTR lpParameters,
3012 _In_opt_ LPSTR lpReturn,
3015 _In_ INT nCmdShow,
3016 _Out_opt_ PHANDLE lphProcess)
3017{
3019 lpOperation,
3020 lpFile,
3021 lpParameters,
3023 lpReturn,
3024 lpTitle,
3025 lpReserved,
3026 nCmdShow,
3027 lphProcess,
3028 0);
3029}
3030
3031/*************************************************************************
3032 * RealShellExecuteW (SHELL32.268)
3033 */
3038 _In_opt_ LPCWSTR lpOperation,
3039 _In_opt_ LPCWSTR lpFile,
3040 _In_opt_ LPCWSTR lpParameters,
3042 _In_opt_ LPWSTR lpReturn,
3045 _In_ INT nCmdShow,
3046 _Out_opt_ PHANDLE lphProcess)
3047{
3049 lpOperation,
3050 lpFile,
3051 lpParameters,
3053 lpReturn,
3054 lpTitle,
3055 lpReserved,
3056 nCmdShow,
3057 lphProcess,
3058 0);
3059}
3060
3061/*************************************************************************
3062 * PathProcessCommandW [Internal]
3063 *
3064 * @see https://learn.microsoft.com/en-us/windows/win32/api/shlobj/nf-shlobj-pathprocesscommand
3065 * @see ./wine/shellpath.c
3066 */
3069 _In_ PCWSTR pszSrc,
3070 _Out_writes_opt_(dwBuffSize) PWSTR pszDest,
3073{
3074 TRACE("%s, %p, %d, 0x%X\n", wine_dbgstr_w(pszSrc), pszDest, cchDest, dwFlags);
3075
3076 if (!pszSrc)
3077 return -1;
3078
3080 PCWSTR pchArg = NULL;
3081
3082 if (*pszSrc == L'"') // Quoted?
3083 {
3084 ++pszSrc;
3085
3086 PCWSTR pch = wcschr(pszSrc, L'"');
3087 if (pch)
3088 {
3089 szPath.SetString(pszSrc, pch - pszSrc);
3090 pchArg = pch + 1;
3091 }
3092 else
3093 {
3094 szPath = pszSrc;
3095 }
3096
3098 {
3100 szPath.ReleaseBuffer();
3101 if (!ret)
3102 return -1;
3103 }
3104 }
3105 else // Not quoted?
3106 {
3107 BOOL resolved = FALSE;
3108 BOOL resolveRelative = PathIsRelativeW(pszSrc) || (dwFlags & PPCF_FORCEQUALIFY);
3109 INT cchPath = 0;
3110
3111 for (INT ich = 0; ; ++ich)
3112 {
3113 szPath += pszSrc[ich];
3114
3115 if (pszSrc[ich] && pszSrc[ich] != L' ')
3116 continue;
3117
3118 szPath = szPath.Left(ich);
3119
3120 if (resolveRelative &&
3122 {
3123 szPath.ReleaseBuffer();
3124 szPath += pszSrc[ich];
3125 }
3126 else
3127 {
3128 szPath.ReleaseBuffer();
3129
3131 if (attrs != INVALID_FILE_ATTRIBUTES &&
3133 {
3134 resolved = TRUE;
3135 pchArg = pszSrc + ich;
3136
3138 break;
3139
3140 cchPath = ich;
3141 break;
3142 }
3143 else if (!resolveRelative)
3144 {
3145 szPath += pszSrc[ich];
3146 }
3147 }
3148
3149 if (!szPath[ich])
3150 {
3151 szPath.ReleaseBuffer(); // Remove excessive '\0'
3152 break;
3153 }
3154 }
3155
3156 if (!resolved)
3157 return -1;
3158
3159 if (cchPath && (dwFlags & PPCF_LONGESTPOSSIBLE))
3160 {
3161 szPath = szPath.Left(cchPath);
3162 pchArg = pszSrc + cchPath;
3163 }
3164 }
3165
3166 BOOL needsQuoting = (dwFlags & PPCF_ADDQUOTES) && wcschr(szPath, L' ');
3167 CStringW result = needsQuoting ? (L"\"" + szPath + L"\"") : szPath;
3168
3169 if (pchArg && (dwFlags & PPCF_ADDARGUMENTS))
3170 result += pchArg;
3171
3172 LONG requiredSize = result.GetLength() + 1;
3173 if (!pszDest)
3174 return requiredSize;
3175
3176 if (requiredSize > cchDest || StringCchCopyW(pszDest, cchDest, result) != S_OK)
3177 return -1;
3178
3179 return requiredSize;
3180}
3181
3182// The common helper of ShellExec_RunDLLA and ShellExec_RunDLLW
3183static VOID
3187 _In_ PCWSTR pszCmdLine,
3188 _In_ INT nCmdShow)
3189{
3190 TRACE("(%p, %p, %s, 0x%X)\n", hwnd, hInstance, wine_dbgstr_w(pszCmdLine), nCmdShow);
3191
3192 if (!pszCmdLine || !*pszCmdLine)
3193 return;
3194
3195 // '?' enables us to specify the additional mask value
3196 ULONG fNewMask = SEE_MASK_NOASYNC;
3197 if (*pszCmdLine == L'?') // 1st question
3198 {
3199 INT MaskValue;
3200 if (StrToIntExW(pszCmdLine + 1, STIF_SUPPORT_HEX, &MaskValue))
3201 fNewMask |= MaskValue;
3202
3203 PCWSTR pch2ndQuestion = StrChrW(pszCmdLine + 1, L'?'); // 2nd question
3204 if (pch2ndQuestion)
3205 pszCmdLine = pch2ndQuestion + 1;
3206 }
3207
3208 WCHAR szPath[2 * MAX_PATH];
3210 if (PathProcessCommandW(pszCmdLine, szPath, _countof(szPath), dwFlags) == -1)
3211 StrCpyNW(szPath, pszCmdLine, _countof(szPath));
3212
3213 // Split arguments from the path
3215 if (*Args)
3216 *(Args - 1) = UNICODE_NULL;
3217
3219
3220 // Execute
3221 SHELLEXECUTEINFOW execInfo = { sizeof(execInfo) };
3222 execInfo.fMask = fNewMask;
3223 execInfo.hwnd = hwnd;
3224 execInfo.lpFile = szPath;
3225 execInfo.lpParameters = Args;
3226 execInfo.nShow = nCmdShow;
3227 if (!ShellExecuteExW(&execInfo))
3228 {
3229 DWORD dwError = GetLastError();
3230 if (SHELL_InRunDllProcess()) // Is it a RUNDLL process?
3231 ExitProcess(dwError); // Terminate it now
3232 }
3233}
3234
3235/*************************************************************************
3236 * ShellExec_RunDLLA [SHELL32.358]
3237 *
3238 * @see https://www.hexacorn.com/blog/2024/11/30/1-little-known-secret-of-shellexec_rundll/
3239 */
3245 _In_ PCSTR pszCmdLine,
3246 _In_ INT nCmdShow)
3247{
3248 CStringW strCmdLine = pszCmdLine; // Keep
3249 ShellExec_RunDLL_Helper(hwnd, hInstance, strCmdLine, nCmdShow);
3250}
3251
3252/*************************************************************************
3253 * ShellExec_RunDLLW [SHELL32.359]
3254 *
3255 * @see https://www.hexacorn.com/blog/2024/11/30/1-little-known-secret-of-shellexec_rundll/
3256 */
3262 _In_ PCWSTR pszCmdLine,
3263 _In_ INT nCmdShow)
3264{
3265 ShellExec_RunDLL_Helper(hwnd, hInstance, pszCmdLine, nCmdShow);
3266}
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
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:97
#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
wcscat
wcscpy
TCHAR lpTitle[80]
Definition: ctm.c:69
static LPCWSTR LPCWSTR LPCWSTR env
Definition: db.cpp:170
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
#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
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 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:4598
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1487
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
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 int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
FxAutoRegKey hKey
size_t total
GLuint start
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLuint GLuint end
Definition: gl.h:1545
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)
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 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 DWORD DWORD void LPSTR DWORD cch
Definition: str.c:202
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
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 _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define KEY_READ
Definition: nt_native.h:1023
#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
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
static const char topic[]
Definition: propsys.c:45
#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 err(...)
#define REGSTR_PATH_EXPLORER
Definition: regstr.h:33
WCHAR classname[128]
Definition: startup.c:15
const WCHAR * str
_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 DECLSPEC_HOTPATCH
Definition: config.h:9
#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
@ REST_SH32_ENABLESHELLEXECUTEHOOKS
Definition: shell32_main.h:41
DWORD SH32_InternalRestricted(DWORD rest)
Definition: shpolicy.c:180
static __inline LPWSTR __SHCloneStrAtoW(WCHAR **target, const char *source)
Definition: shell32_main.h:204
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
#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
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:1759
static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:1648
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExA(LPSHELLEXECUTEINFOA sei)
Definition: shlexec.cpp:2494
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:3259
HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
Definition: shlexec.cpp:1410
static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:1575
static void do_error_dialog(UINT_PTR retval, HWND hwnd, PCWSTR filename)
Definition: shlexec.cpp:1996
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:1874
EXTERN_C void WINAPI OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow)
Definition: shlexec.cpp:2684
static LPCWSTR SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0)
Definition: shlexec.cpp:2698
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:2939
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:1308
EXTERN_C void WINAPI OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow)
Definition: shlexec.cpp:2673
static LONG ShellExecute_FromContextMenuHandlers(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:1714
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:863
static DWORD ShellExecute_Normal(_Inout_ LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2466
EXTERN_C VOID WINAPI ShellExec_RunDLLA(_In_opt_ HWND hwnd, _In_opt_ HINSTANCE hInstance, _In_ PCSTR pszCmdLine, _In_ INT nCmdShow)
Definition: shlexec.cpp:3242
EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback)
Definition: shlexec.cpp:2638
static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
Definition: shlexec.cpp:2038
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:1081
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:2017
static HRESULT TryShellExecuteHooks(LPSHELLEXECUTEINFOW pSEI)
Definition: shlexec.cpp:122
HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
Definition: shlexec.cpp:1367
static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
Definition: shlexec.cpp:1962
EXTERN_C LONG PathProcessCommandW(_In_ PCWSTR pszSrc, _Out_writes_opt_(dwBuffSize) PWSTR pszDest, _In_ INT cchDest, _In_ DWORD dwFlags)
Definition: shlexec.cpp:3068
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:1099
static VOID ShellExecute_ShowError(_In_ const SHELLEXECUTEINFOW *ExecInfo, _In_opt_ LPCWSTR pszCaption, _In_ DWORD dwError)
Definition: shlexec.cpp:2480
EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath)
Definition: shellpath.c:539
static HRESULT shellex_run_context_menu_default(IShellExtInit *obj, LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:1506
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:2607
static UINT SHELL_FindExecutableByVerb(LPCWSTR lpVerb, LPWSTR key, LPWSTR classname, LPWSTR command, LONG commandlen)
Definition: shlexec.cpp:795
static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
Definition: shlexec.cpp:573
static BOOL SHELL_InRunDllProcess(VOID)
Definition: shlexec.cpp:73
static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen)
Definition: shlexec.cpp:1818
static HKEY ShellExecute_GetClassKey(const SHELLEXECUTEINFOW *sei)
Definition: shlexec.cpp:1462
static HRESULT shellex_get_contextmenu(LPSHELLEXECUTEINFOW sei, CComPtr< IContextMenu > &cm)
Definition: shlexec.cpp:1609
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:3006
static HRESULT shellex_get_dataobj(LPSHELLEXECUTEINFOW sei, CComPtr< IDataObject > &dataObj)
Definition: shlexec.cpp:1481
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2552
static VOID ShellExec_RunDLL_Helper(_In_opt_ HWND hwnd, _In_opt_ HINSTANCE hInstance, _In_ PCWSTR pszCmdLine, _In_ INT nCmdShow)
Definition: shlexec.cpp:3184
static LPWSTR SHELL_BuildEnvW(const WCHAR *path)
Definition: shlexec.cpp:677
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:2436
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:2872
static BOOL SHELL_TryAppPathW(LPCWSTR szName, LPWSTR lpResult, WCHAR **env)
Definition: shlexec.cpp:735
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:1926
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:3036
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 UrlIsFileUrlW(x)
Definition: shlwapi.h:1423
@ ASSOCSTR_COMMAND
Definition: shlwapi.h:612
@ ASSOCSTR_EXECUTABLE
Definition: shlwapi.h:613
#define STIF_SUPPORT_HEX
Definition: shlwapi.h:1498
@ ASSOCF_NONE
Definition: shlwapi.h:590
@ URLIS_APPLIABLE
Definition: shlwapi.h:1238
#define WHICH_DEFAULT
#define SHACF_WIN95SHLEXEC
#define IDS_FILE_NOT_FOUND
Definition: shresdef.h:373
#define IDS_SHLEXEC_NOASSOC
Definition: shresdef.h:187
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
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
HANDLE HINSTANCE
Definition: typedefs.h:77
uint16_t * PWSTR
Definition: typedefs.h:56
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:684
#define SEE_MASK_FLAG_SEPVDM
Definition: undocshell.h:683
#define SEE_MASK_HASTITLE
Definition: undocshell.h:685
#define SEE_MASK_NO_HOOKS
Definition: undocshell.h:681
#define SEE_MASK_UNKNOWN_0x1000
Definition: undocshell.h:680
#define SEE_MASK_HASLINKNAME
Definition: undocshell.h:682
#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
#define ZeroMemory
Definition: winbase.h:1753
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define STARTF_USESHOWWINDOW
Definition: winbase.h:524
#define CREATE_UNICODE_ENVIRONMENT
Definition: winbase.h:196
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:456
#define CREATE_SEPARATE_WOW_VDM
Definition: winbase.h:197
#define FORMAT_MESSAGE_ARGUMENT_ARRAY
Definition: winbase.h:457
#define WAIT_FAILED
Definition: winbase.h:446
#define EXCEPTION_ACCESS_VIOLATION
Definition: winbase.h:344
#define CREATE_NEW_CONSOLE
Definition: winbase.h:190
struct _STARTUPINFOW STARTUPINFOW
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LRESULT
Definition: windef.h:209
#define WINAPI
Definition: msvc.h:6
#define S_FALSE
Definition: winerror.h:3452
static HRESULT HRESULT_FROM_WIN32(unsigned int x)
Definition: winerror.h:211
#define ERROR_APP_WRONG_OS
Definition: winerror.h:998
#define ERROR_SHARING_VIOLATION
Definition: winerror.h:258
#define ERROR_RMODE_APP
Definition: winerror.h:1000
#define ERROR_DDE_FAIL
Definition: winerror.h:1003
#define ERROR_DLL_NOT_FOUND
Definition: winerror.h:1004
#define ERROR_NO_ASSOCIATION
Definition: winerror.h:1002
#define ERROR_INVALID_DLL
Definition: winerror.h:1001
#define ERROR_CANCELLED
Definition: winerror.h:1056
#define CO_E_APPNOTFOUND
Definition: winerror.h:3922
#define ERROR_SINGLE_INSTANCE_APP
Definition: winerror.h:999
#define ERROR_BAD_FORMAT
Definition: winerror.h:237
#define ERROR_OLD_WIN_VERSION
Definition: winerror.h:997
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:1334
_In_ DWORD _In_ int _In_ int _In_opt_ LPNLSVERSIONINFO _In_opt_ LPVOID lpReserved
Definition: winnls.h:1199
_In_ DWORD _In_ int _In_ int cchDest
Definition: winnls.h:1197
#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 MIIM_STRING
Definition: winuser.h:738
#define MIIM_ID
Definition: winuser.h:733
int WINAPI GetMenuItemCount(_In_opt_ HMENU)
HMENU WINAPI CreateMenu(void)
Definition: menu.c:829
#define MIIM_FTYPE
Definition: winuser.h:740
int WINAPI MessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType)
#define MIIM_STATE
Definition: winuser.h:732
#define MFS_DEFAULT
Definition: winuser.h:759
#define SW_SHOWDEFAULT
Definition: winuser.h:791
#define MB_ICONERROR
Definition: winuser.h:798
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 SW_SHOW
Definition: winuser.h:786
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define MIIM_DATA
Definition: winuser.h:737
#define IID_PPV_ARG(Itype, ppType)
#define IID_NULL_PPV_ARG(Itype, ppType)
const char * LPCSTR
Definition: xmlstorage.h:183
char * LPSTR
Definition: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185