xref: /reactos/dll/win32/shell32/shlexec.cpp (revision dad3a093)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  *          Shell Library Functions
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 1998 Marcus Meissner
5c2c66affSColin Finck  * Copyright 2002 Eric Pouech
6044f1819SKatayama Hirofumi MZ  * Copyright 2018-2024 Katayama Hirofumi MZ
7c2c66affSColin Finck  *
8c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
9c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
10c2c66affSColin Finck  * License as published by the Free Software Foundation; either
11c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
12c2c66affSColin Finck  *
13c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
14c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16c2c66affSColin Finck  * Lesser General Public License for more details.
17c2c66affSColin Finck  *
18c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
19c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
20c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21c2c66affSColin Finck  */
22c2c66affSColin Finck 
23c2c66affSColin Finck #include "precomp.h"
24bfcbda22SKatayama Hirofumi MZ #include <undocshell.h>
25c2c66affSColin Finck 
26c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(exec);
27c2c66affSColin Finck 
289b716539SAlex Miccolis EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath);
299b716539SAlex Miccolis 
30c2c66affSColin Finck #define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)
31c2c66affSColin Finck 
32c2c66affSColin Finck typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
33c2c66affSColin Finck                 const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out);
34c2c66affSColin Finck 
35044f1819SKatayama Hirofumi MZ // Is the current process a rundll32.exe?
SHELL_InRunDllProcess(VOID)36044f1819SKatayama Hirofumi MZ static BOOL SHELL_InRunDllProcess(VOID)
37044f1819SKatayama Hirofumi MZ {
38044f1819SKatayama Hirofumi MZ     WCHAR szModule[MAX_PATH];
39044f1819SKatayama Hirofumi MZ     static INT s_bInDllProcess = -1;
40044f1819SKatayama Hirofumi MZ 
41044f1819SKatayama Hirofumi MZ     if (s_bInDllProcess != -1)
42044f1819SKatayama Hirofumi MZ         return s_bInDllProcess;
43044f1819SKatayama Hirofumi MZ 
44044f1819SKatayama Hirofumi MZ     s_bInDllProcess = GetModuleFileNameW(NULL, szModule, _countof(szModule)) &&
45044f1819SKatayama Hirofumi MZ                       (StrStrIW(PathFindFileNameW(szModule), L"rundll") != NULL);
46044f1819SKatayama Hirofumi MZ     return s_bInDllProcess;
47044f1819SKatayama Hirofumi MZ }
48044f1819SKatayama Hirofumi MZ 
ParseNoTildeEffect(PWSTR & res,LPCWSTR & args,DWORD & len,DWORD & used,int argNum)49c2c66affSColin Finck static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
50c2c66affSColin Finck {
51c2c66affSColin Finck     bool firstCharQuote = false;
52c2c66affSColin Finck     bool quotes_opened = false;
53c2c66affSColin Finck     bool backslash_encountered = false;
54c2c66affSColin Finck 
55c2c66affSColin Finck     for (int curArg = 0; curArg <= argNum && *args; ++curArg)
56c2c66affSColin Finck     {
57c2c66affSColin Finck         firstCharQuote = false;
58c2c66affSColin Finck         if (*args == '"')
59c2c66affSColin Finck         {
60c2c66affSColin Finck             quotes_opened = true;
61c2c66affSColin Finck             firstCharQuote = true;
62c2c66affSColin Finck             args++;
63c2c66affSColin Finck         }
64c2c66affSColin Finck 
65c2c66affSColin Finck         while(*args)
66c2c66affSColin Finck         {
67c2c66affSColin Finck             if (*args == '\\')
68c2c66affSColin Finck             {
69c2c66affSColin Finck                 // if we found a backslash then flip the variable
70c2c66affSColin Finck                 backslash_encountered = !backslash_encountered;
71c2c66affSColin Finck             }
72c2c66affSColin Finck             else if (*args == '"')
73c2c66affSColin Finck             {
74c2c66affSColin Finck                 if (quotes_opened)
75c2c66affSColin Finck                 {
76c2c66affSColin Finck                     if (*(args + 1) != '"')
77c2c66affSColin Finck                     {
78c2c66affSColin Finck                         quotes_opened = false;
79c2c66affSColin Finck                         args++;
80c2c66affSColin Finck                         break;
81c2c66affSColin Finck                     }
82c2c66affSColin Finck                     else
83c2c66affSColin Finck                     {
84c2c66affSColin Finck                         args++;
85c2c66affSColin Finck                     }
86c2c66affSColin Finck                 }
87c2c66affSColin Finck                 else
88c2c66affSColin Finck                 {
89c2c66affSColin Finck                     quotes_opened = true;
90c2c66affSColin Finck                 }
91c2c66affSColin Finck 
92c2c66affSColin Finck                 backslash_encountered = false;
93c2c66affSColin Finck             }
94c2c66affSColin Finck             else
95c2c66affSColin Finck             {
96c2c66affSColin Finck                 backslash_encountered = false;
97c2c66affSColin Finck                 if (*args == ' ' && !firstCharQuote)
98c2c66affSColin Finck                     break;
99c2c66affSColin Finck             }
100c2c66affSColin Finck 
101c2c66affSColin Finck             if (curArg == argNum)
102c2c66affSColin Finck             {
103c2c66affSColin Finck                 used++;
104c2c66affSColin Finck                 if (used < len)
105c2c66affSColin Finck                     *res++ = *args;
106c2c66affSColin Finck             }
107c2c66affSColin Finck 
108c2c66affSColin Finck             args++;
109c2c66affSColin Finck         }
110c2c66affSColin Finck 
111c2c66affSColin Finck         while(*args == ' ')
112c2c66affSColin Finck             ++args;
113c2c66affSColin Finck     }
114c2c66affSColin Finck }
115c2c66affSColin Finck 
ParseTildeEffect(PWSTR & res,LPCWSTR & args,DWORD & len,DWORD & used,int argNum)116c2c66affSColin Finck static void ParseTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
117c2c66affSColin Finck {
118c2c66affSColin Finck     bool quotes_opened = false;
119c2c66affSColin Finck     bool backslash_encountered = false;
120c2c66affSColin Finck 
121c2c66affSColin Finck     for (int curArg = 0; curArg <= argNum && *args; ++curArg)
122c2c66affSColin Finck     {
123c2c66affSColin Finck         while(*args)
124c2c66affSColin Finck         {
125c2c66affSColin Finck             if (*args == '\\')
126c2c66affSColin Finck             {
127c2c66affSColin Finck                 // if we found a backslash then flip the variable
128c2c66affSColin Finck                 backslash_encountered = !backslash_encountered;
129c2c66affSColin Finck             }
130c2c66affSColin Finck             else if (*args == '"')
131c2c66affSColin Finck             {
132c2c66affSColin Finck                 if (quotes_opened)
133c2c66affSColin Finck                 {
134c2c66affSColin Finck                     if (*(args + 1) != '"')
135c2c66affSColin Finck                     {
136c2c66affSColin Finck                         quotes_opened = false;
137c2c66affSColin Finck                     }
138c2c66affSColin Finck                     else
139c2c66affSColin Finck                     {
140c2c66affSColin Finck                         args++;
141c2c66affSColin Finck                     }
142c2c66affSColin Finck                 }
143c2c66affSColin Finck                 else
144c2c66affSColin Finck                 {
145c2c66affSColin Finck                     quotes_opened = true;
146c2c66affSColin Finck                 }
147c2c66affSColin Finck 
148c2c66affSColin Finck                 backslash_encountered = false;
149c2c66affSColin Finck             }
150c2c66affSColin Finck             else
151c2c66affSColin Finck             {
152c2c66affSColin Finck                 backslash_encountered = false;
153c2c66affSColin Finck                 if (*args == ' ' && !quotes_opened && curArg != argNum)
154c2c66affSColin Finck                     break;
155c2c66affSColin Finck             }
156c2c66affSColin Finck 
157c2c66affSColin Finck             if (curArg == argNum)
158c2c66affSColin Finck             {
159c2c66affSColin Finck                 used++;
160c2c66affSColin Finck                 if (used < len)
161c2c66affSColin Finck                     *res++ = *args;
162c2c66affSColin Finck             }
163c2c66affSColin Finck 
164c2c66affSColin Finck             args++;
165c2c66affSColin Finck         }
166c2c66affSColin Finck     }
167c2c66affSColin Finck }
168c2c66affSColin Finck 
169c2c66affSColin Finck /***********************************************************************
170c2c66affSColin Finck  * SHELL_ArgifyW [Internal]
171c2c66affSColin Finck  *
172c2c66affSColin Finck  * this function is supposed to expand the escape sequences found in the registry
173c2c66affSColin Finck  * some diving reported that the following were used:
174c2c66affSColin Finck  * + %1, %2...  seem to report to parameter of index N in ShellExecute pmts
175c2c66affSColin Finck  * %1 file
176c2c66affSColin Finck  * %2 printer
177c2c66affSColin Finck  * %3 driver
178c2c66affSColin Finck  * %4 port
179c2c66affSColin Finck  * %I address of a global item ID (explorer switch /idlist)
180c2c66affSColin Finck  * %L seems to be %1 as long filename followed by the 8+3 variation
181c2c66affSColin Finck  * %S ???
18290c63d12SKatayama Hirofumi MZ  * %W Working directory
18390c63d12SKatayama Hirofumi MZ  * %V Use either %L or %W
184c2c66affSColin Finck  * %* all following parameters (see batfile)
185c2c66affSColin Finck  *
186c2c66affSColin Finck  * The way we parse the command line arguments was determined through extensive
187c2c66affSColin Finck  * testing and can be summed up by the following rules"
188c2c66affSColin Finck  *
189c2c66affSColin Finck  * - %2
190c2c66affSColin Finck  *     - if first letter is " break on first non literal " and include any white spaces
191c2c66affSColin Finck  *     - if first letter is NOT " break on first " or white space
192c2c66affSColin Finck  *     - if " is opened any pair of consecutive " results in ONE literal "
193c2c66affSColin Finck  *
194c2c66affSColin Finck  * - %~2
195c2c66affSColin Finck  *     - use rules from here http://www.autohotkey.net/~deleyd/parameters/parameters.htm
196c2c66affSColin Finck  */
197c2c66affSColin Finck 
SHELL_ArgifyW(WCHAR * out,DWORD len,const WCHAR * fmt,const WCHAR * lpFile,LPITEMIDLIST pidl,LPCWSTR args,DWORD * out_len,const WCHAR * lpDir)198e018cceaSKatayama Hirofumi MZ static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len, const WCHAR* lpDir)
199c2c66affSColin Finck {
200c2c66affSColin Finck     BOOL    done = FALSE;
201c2c66affSColin Finck     BOOL    found_p1 = FALSE;
202c2c66affSColin Finck     PWSTR   res = out;
203c2c66affSColin Finck     DWORD   used = 0;
204c2c66affSColin Finck     bool    tildeEffect = false;
205c2c66affSColin Finck 
206c2c66affSColin Finck     TRACE("Before parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
207c2c66affSColin Finck           debugstr_w(lpFile), pidl, args);
208c2c66affSColin Finck 
209c2c66affSColin Finck     while (*fmt)
210c2c66affSColin Finck     {
211c2c66affSColin Finck         if (*fmt == '%')
212c2c66affSColin Finck         {
213c2c66affSColin Finck             switch (*++fmt)
214c2c66affSColin Finck             {
215c2c66affSColin Finck                 case '\0':
216c2c66affSColin Finck                 case '%':
217c2c66affSColin Finck                 {
218c2c66affSColin Finck                     used++;
219c2c66affSColin Finck                     if (used < len)
220c2c66affSColin Finck                         *res++ = '%';
221c2c66affSColin Finck                 };
222c2c66affSColin Finck                 break;
223c2c66affSColin Finck 
224c2c66affSColin Finck                 case '*':
225c2c66affSColin Finck                 {
226c2c66affSColin Finck                     if (args)
227c2c66affSColin Finck                     {
228c2c66affSColin Finck                         if (*fmt == '*')
229c2c66affSColin Finck                         {
230c2c66affSColin Finck                             used++;
231c2c66affSColin Finck                             while(*args)
232c2c66affSColin Finck                             {
233c2c66affSColin Finck                                 used++;
234c2c66affSColin Finck                                 if (used < len)
235c2c66affSColin Finck                                     *res++ = *args++;
236c2c66affSColin Finck                                 else
237c2c66affSColin Finck                                     args++;
238c2c66affSColin Finck                             }
239c2c66affSColin Finck                             used++;
240c2c66affSColin Finck                             break;
241c2c66affSColin Finck                         }
242c2c66affSColin Finck                     }
243c2c66affSColin Finck                 };
244c2c66affSColin Finck                 break;
245c2c66affSColin Finck 
246c2c66affSColin Finck                 case '~':
247c2c66affSColin Finck 
248c2c66affSColin Finck                 case '2':
249c2c66affSColin Finck                 case '3':
250c2c66affSColin Finck                 case '4':
251c2c66affSColin Finck                 case '5':
252c2c66affSColin Finck                 case '6':
253c2c66affSColin Finck                 case '7':
254c2c66affSColin Finck                 case '8':
255c2c66affSColin Finck                 case '9':
256c2c66affSColin Finck                     //case '0':
257c2c66affSColin Finck                 {
258c2c66affSColin Finck                     if (*fmt == '~')
259c2c66affSColin Finck                     {
260c2c66affSColin Finck                         fmt++;
261c2c66affSColin Finck                         tildeEffect = true;
262c2c66affSColin Finck                     }
263c2c66affSColin Finck 
264c2c66affSColin Finck                     if (args)
265c2c66affSColin Finck                     {
266c2c66affSColin Finck                         if (tildeEffect)
267c2c66affSColin Finck                         {
268c2c66affSColin Finck                             ParseTildeEffect(res, args, len, used, *fmt - '2');
269c2c66affSColin Finck                             tildeEffect = false;
270c2c66affSColin Finck                         }
271c2c66affSColin Finck                         else
272c2c66affSColin Finck                         {
273c2c66affSColin Finck                             ParseNoTildeEffect(res, args, len, used, *fmt - '2');
274c2c66affSColin Finck                         }
275c2c66affSColin Finck                     }
276c2c66affSColin Finck                 };
277c2c66affSColin Finck                 break;
278c2c66affSColin Finck 
279c2c66affSColin Finck                 case '1':
280e5a6b0f8SOleg Dubinskiy                     if ((!done || (*fmt == '1')) && lpFile)
281c2c66affSColin Finck                     {
282e5a6b0f8SOleg Dubinskiy                         SIZE_T filelen = wcslen(lpFile);
283e5a6b0f8SOleg Dubinskiy                         used += filelen;
284c2c66affSColin Finck                         if (used < len)
285c2c66affSColin Finck                         {
286e5a6b0f8SOleg Dubinskiy                             wcscpy(res, lpFile);
287e5a6b0f8SOleg Dubinskiy                             res += filelen;
288c2c66affSColin Finck                         }
289c2c66affSColin Finck                     }
290c2c66affSColin Finck                     found_p1 = TRUE;
291c2c66affSColin Finck                     break;
292c2c66affSColin Finck 
293c2c66affSColin Finck                     /*
294c2c66affSColin Finck                      * IE uses this a lot for activating things such as windows media
295c2c66affSColin Finck                      * player. This is not verified to be fully correct but it appears
296c2c66affSColin Finck                      * to work just fine.
297c2c66affSColin Finck                      */
298c2c66affSColin Finck                 case 'l':
299c2c66affSColin Finck                 case 'L':
300c2c66affSColin Finck                     if (lpFile)
301c2c66affSColin Finck                     {
302c2c66affSColin Finck                         used += wcslen(lpFile);
303c2c66affSColin Finck                         if (used < len)
304c2c66affSColin Finck                         {
305c2c66affSColin Finck                             wcscpy(res, lpFile);
306c2c66affSColin Finck                             res += wcslen(lpFile);
307c2c66affSColin Finck                         }
308c2c66affSColin Finck                     }
309c2c66affSColin Finck                     found_p1 = TRUE;
310c2c66affSColin Finck                     break;
311c2c66affSColin Finck 
31290c63d12SKatayama Hirofumi MZ                 case 'w':
31390c63d12SKatayama Hirofumi MZ                 case 'W':
31490c63d12SKatayama Hirofumi MZ                     if (lpDir)
31590c63d12SKatayama Hirofumi MZ                     {
31690c63d12SKatayama Hirofumi MZ                         used += wcslen(lpDir);
31790c63d12SKatayama Hirofumi MZ                         if (used < len)
31890c63d12SKatayama Hirofumi MZ                         {
31990c63d12SKatayama Hirofumi MZ                             wcscpy(res, lpDir);
32090c63d12SKatayama Hirofumi MZ                             res += wcslen(lpDir);
32190c63d12SKatayama Hirofumi MZ                         }
32290c63d12SKatayama Hirofumi MZ                     }
32390c63d12SKatayama Hirofumi MZ                     break;
32490c63d12SKatayama Hirofumi MZ 
32590c63d12SKatayama Hirofumi MZ                 case 'v':
32690c63d12SKatayama Hirofumi MZ                 case 'V':
32790c63d12SKatayama Hirofumi MZ                     if (lpFile)
32890c63d12SKatayama Hirofumi MZ                     {
32990c63d12SKatayama Hirofumi MZ                         used += wcslen(lpFile);
33090c63d12SKatayama Hirofumi MZ                         if (used < len)
33190c63d12SKatayama Hirofumi MZ                         {
33290c63d12SKatayama Hirofumi MZ                             wcscpy(res, lpFile);
33390c63d12SKatayama Hirofumi MZ                             res += wcslen(lpFile);
33490c63d12SKatayama Hirofumi MZ                         }
33590c63d12SKatayama Hirofumi MZ                         found_p1 = TRUE;
33690c63d12SKatayama Hirofumi MZ                     }
33790c63d12SKatayama Hirofumi MZ                     else if (lpDir)
33890c63d12SKatayama Hirofumi MZ                     {
33990c63d12SKatayama Hirofumi MZ                         used += wcslen(lpDir);
34090c63d12SKatayama Hirofumi MZ                         if (used < len)
34190c63d12SKatayama Hirofumi MZ                         {
34290c63d12SKatayama Hirofumi MZ                             wcscpy(res, lpDir);
34390c63d12SKatayama Hirofumi MZ                             res += wcslen(lpDir);
34490c63d12SKatayama Hirofumi MZ                         }
34590c63d12SKatayama Hirofumi MZ                     }
34690c63d12SKatayama Hirofumi MZ                     break;
34790c63d12SKatayama Hirofumi MZ 
348c2c66affSColin Finck                 case 'i':
349c2c66affSColin Finck                 case 'I':
350c2c66affSColin Finck                     if (pidl)
351c2c66affSColin Finck                     {
352c2c66affSColin Finck                         DWORD chars = 0;
353c2c66affSColin Finck                         /* %p should not exceed 8, maybe 16 when looking forward to 64bit.
354c2c66affSColin Finck                             * allowing a buffer of 100 should more than exceed all needs */
355c2c66affSColin Finck                         WCHAR buf[100];
356c2c66affSColin Finck                         LPVOID  pv;
357c2c66affSColin Finck                         HGLOBAL hmem = SHAllocShared(pidl, ILGetSize(pidl), 0);
358c2c66affSColin Finck                         pv = SHLockShared(hmem, 0);
359c2c66affSColin Finck                         chars = swprintf(buf, L":%p", pv);
360c2c66affSColin Finck 
36183be315aSHermès Bélusca-Maïto                         if (chars >= ARRAY_SIZE(buf))
362c2c66affSColin Finck                             ERR("pidl format buffer too small!\n");
363c2c66affSColin Finck 
364c2c66affSColin Finck                         used += chars;
365c2c66affSColin Finck 
366c2c66affSColin Finck                         if (used < len)
367c2c66affSColin Finck                         {
368c2c66affSColin Finck                             wcscpy(res, buf);
369c2c66affSColin Finck                             res += chars;
370c2c66affSColin Finck                         }
371c2c66affSColin Finck                         SHUnlockShared(pv);
372c2c66affSColin Finck                     }
373c2c66affSColin Finck                     found_p1 = TRUE;
374c2c66affSColin Finck                     break;
375c2c66affSColin Finck 
376c2c66affSColin Finck                 default:
377c2c66affSColin Finck                     /*
378c2c66affSColin Finck                      * Check if this is an env-variable here...
379c2c66affSColin Finck                      */
380c2c66affSColin Finck 
381c2c66affSColin Finck                     /* Make sure that we have at least one more %.*/
382c2c66affSColin Finck                     if (strchrW(fmt, '%'))
383c2c66affSColin Finck                     {
384c2c66affSColin Finck                         WCHAR   tmpBuffer[1024];
385c2c66affSColin Finck                         PWSTR   tmpB = tmpBuffer;
386c2c66affSColin Finck                         WCHAR   tmpEnvBuff[MAX_PATH];
387c2c66affSColin Finck                         DWORD   envRet;
388c2c66affSColin Finck 
389c2c66affSColin Finck                         while (*fmt != '%')
390c2c66affSColin Finck                             *tmpB++ = *fmt++;
391c2c66affSColin Finck                         *tmpB++ = 0;
392c2c66affSColin Finck 
393c2c66affSColin Finck                         TRACE("Checking %s to be an env-var\n", debugstr_w(tmpBuffer));
394c2c66affSColin Finck 
395c2c66affSColin Finck                         envRet = GetEnvironmentVariableW(tmpBuffer, tmpEnvBuff, MAX_PATH);
396c2c66affSColin Finck                         if (envRet == 0 || envRet > MAX_PATH)
397c2c66affSColin Finck                         {
398c2c66affSColin Finck                             used += wcslen(tmpBuffer);
399c2c66affSColin Finck                             if (used < len)
400c2c66affSColin Finck                             {
401c2c66affSColin Finck                                 wcscpy( res, tmpBuffer );
402c2c66affSColin Finck                                 res += wcslen(tmpBuffer);
403c2c66affSColin Finck                             }
404c2c66affSColin Finck                         }
405c2c66affSColin Finck                         else
406c2c66affSColin Finck                         {
407c2c66affSColin Finck                             used += wcslen(tmpEnvBuff);
408c2c66affSColin Finck                             if (used < len)
409c2c66affSColin Finck                             {
410c2c66affSColin Finck                                 wcscpy( res, tmpEnvBuff );
411c2c66affSColin Finck                                 res += wcslen(tmpEnvBuff);
412c2c66affSColin Finck                             }
413c2c66affSColin Finck                         }
414c2c66affSColin Finck                     }
415c2c66affSColin Finck                     done = TRUE;
416c2c66affSColin Finck                     break;
417c2c66affSColin Finck             }
418c2c66affSColin Finck             /* Don't skip past terminator (catch a single '%' at the end) */
419c2c66affSColin Finck             if (*fmt != '\0')
420c2c66affSColin Finck             {
421c2c66affSColin Finck                 fmt++;
422c2c66affSColin Finck             }
423c2c66affSColin Finck         }
424c2c66affSColin Finck         else
425c2c66affSColin Finck         {
426c2c66affSColin Finck             used ++;
427c2c66affSColin Finck             if (used < len)
428c2c66affSColin Finck                 *res++ = *fmt++;
429c2c66affSColin Finck             else
430c2c66affSColin Finck                 fmt++;
431c2c66affSColin Finck         }
432c2c66affSColin Finck     }
433c2c66affSColin Finck 
434c2c66affSColin Finck     used++;
435c2c66affSColin Finck     if (res - out < static_cast<int>(len))
436c2c66affSColin Finck         *res = '\0';
437c2c66affSColin Finck     else
438c2c66affSColin Finck         out[len-1] = '\0';
439c2c66affSColin Finck 
440c2c66affSColin Finck     TRACE("used %i of %i space\n", used, len);
441c2c66affSColin Finck     if (out_len)
442c2c66affSColin Finck         *out_len = used;
443c2c66affSColin Finck 
444c2c66affSColin Finck     TRACE("After parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
445c2c66affSColin Finck           debugstr_w(lpFile), pidl, args);
446c2c66affSColin Finck 
447c2c66affSColin Finck     return found_p1;
448c2c66affSColin Finck }
449c2c66affSColin Finck 
SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl,LPWSTR pszPath,UINT uOutSize)450c2c66affSColin Finck static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR pszPath, UINT uOutSize)
451c2c66affSColin Finck {
452c2c66affSColin Finck     STRRET strret;
453c2c66affSColin Finck     CComPtr<IShellFolder> desktop;
454c2c66affSColin Finck 
455c2c66affSColin Finck     HRESULT hr = SHGetDesktopFolder(&desktop);
456c2c66affSColin Finck 
457c2c66affSColin Finck     if (SUCCEEDED(hr))
458c2c66affSColin Finck     {
459c2c66affSColin Finck         hr = desktop->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
460c2c66affSColin Finck 
461c2c66affSColin Finck         if (SUCCEEDED(hr))
462c2c66affSColin Finck             StrRetToStrNW(pszPath, uOutSize, &strret, pidl);
463c2c66affSColin Finck     }
464c2c66affSColin Finck 
465c2c66affSColin Finck     return hr;
466c2c66affSColin Finck }
467c2c66affSColin Finck 
468c2c66affSColin Finck /*************************************************************************
469c2c66affSColin Finck  *    SHELL_ExecuteW [Internal]
470c2c66affSColin Finck  *
471c2c66affSColin Finck  */
SHELL_ExecuteW(const WCHAR * lpCmd,WCHAR * env,BOOL shWait,const SHELLEXECUTEINFOW * psei,LPSHELLEXECUTEINFOW psei_out)472c2c66affSColin Finck static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
473c2c66affSColin Finck                                const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
474c2c66affSColin Finck {
475c2c66affSColin Finck     STARTUPINFOW  startup;
476c2c66affSColin Finck     PROCESS_INFORMATION info;
477c2c66affSColin Finck     UINT_PTR retval = SE_ERR_NOASSOC;
478c2c66affSColin Finck     UINT gcdret = 0;
479c2c66affSColin Finck     WCHAR curdir[MAX_PATH];
480c2c66affSColin Finck     DWORD dwCreationFlags;
481c2c66affSColin Finck     const WCHAR *lpDirectory = NULL;
482c2c66affSColin Finck 
483c2c66affSColin Finck     TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory));
484c2c66affSColin Finck 
485c2c66affSColin Finck     /* make sure we don't fail the CreateProcess if the calling app passes in
486c2c66affSColin Finck      * a bad working directory */
487724b20d4SWhindmar Saksit     if (!StrIsNullOrEmpty(psei->lpDirectory))
488c2c66affSColin Finck     {
489c2c66affSColin Finck         DWORD attr = GetFileAttributesW(psei->lpDirectory);
490c2c66affSColin Finck         if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY)
491c2c66affSColin Finck             lpDirectory = psei->lpDirectory;
492c2c66affSColin Finck     }
493c2c66affSColin Finck 
494c2c66affSColin Finck     /* ShellExecute specifies the command from psei->lpDirectory
495c2c66affSColin Finck      * if present. Not from the current dir as CreateProcess does */
496c2c66affSColin Finck     if (lpDirectory)
497c2c66affSColin Finck         if ((gcdret = GetCurrentDirectoryW( MAX_PATH, curdir)))
498c2c66affSColin Finck             if (!SetCurrentDirectoryW( lpDirectory))
499c2c66affSColin Finck                 ERR("cannot set directory %s\n", debugstr_w(lpDirectory));
500c2c66affSColin Finck 
501c2c66affSColin Finck     ZeroMemory(&startup, sizeof(STARTUPINFOW));
502c2c66affSColin Finck     startup.cb = sizeof(STARTUPINFOW);
503c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
504c2c66affSColin Finck     startup.wShowWindow = psei->nShow;
505c2c66affSColin Finck     dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
506c2c66affSColin Finck     if (!(psei->fMask & SEE_MASK_NO_CONSOLE))
507c2c66affSColin Finck         dwCreationFlags |= CREATE_NEW_CONSOLE;
50851b662f9SKatayama Hirofumi MZ     if (psei->fMask & SEE_MASK_FLAG_SEPVDM)
50951b662f9SKatayama Hirofumi MZ         dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
510c2c66affSColin Finck     startup.lpTitle = (LPWSTR)(psei->fMask & (SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE) ? psei->lpClass : NULL);
511c2c66affSColin Finck 
512c2c66affSColin Finck     if (psei->fMask & SEE_MASK_HASLINKNAME)
513c2c66affSColin Finck         startup.dwFlags |= STARTF_TITLEISLINKNAME;
514c2c66affSColin Finck 
515c2c66affSColin Finck     if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
516c2c66affSColin Finck                        lpDirectory, &startup, &info))
517c2c66affSColin Finck     {
518c2c66affSColin Finck         /* Give 30 seconds to the app to come up, if desired. Probably only needed
519c2c66affSColin Finck            when starting app immediately before making a DDE connection. */
520c2c66affSColin Finck         if (shWait)
521c2c66affSColin Finck             if (WaitForInputIdle(info.hProcess, 30000) == WAIT_FAILED)
522c2c66affSColin Finck                 WARN("WaitForInputIdle failed: Error %d\n", GetLastError() );
523c2c66affSColin Finck         retval = 33;
524c2c66affSColin Finck 
525c2c66affSColin Finck         if (psei->fMask & SEE_MASK_NOCLOSEPROCESS)
526c2c66affSColin Finck             psei_out->hProcess = info.hProcess;
527c2c66affSColin Finck         else
528c2c66affSColin Finck             CloseHandle( info.hProcess );
529c2c66affSColin Finck         CloseHandle( info.hThread );
530c2c66affSColin Finck     }
531c2c66affSColin Finck     else if ((retval = GetLastError()) >= 32)
532c2c66affSColin Finck     {
533c2c66affSColin Finck         WARN("CreateProcess returned error %ld\n", retval);
534c2c66affSColin Finck         retval = ERROR_BAD_FORMAT;
535c2c66affSColin Finck     }
536c2c66affSColin Finck 
537c2c66affSColin Finck     TRACE("returning %lu\n", retval);
538c2c66affSColin Finck 
539c2c66affSColin Finck     psei_out->hInstApp = (HINSTANCE)retval;
540c2c66affSColin Finck 
541c2c66affSColin Finck     if (gcdret)
542c2c66affSColin Finck         if (!SetCurrentDirectoryW(curdir))
543c2c66affSColin Finck             ERR("cannot return to directory %s\n", debugstr_w(curdir));
544c2c66affSColin Finck 
545c2c66affSColin Finck     return retval;
546c2c66affSColin Finck }
547c2c66affSColin Finck 
548c2c66affSColin Finck 
549c2c66affSColin Finck /***********************************************************************
550c2c66affSColin Finck  *           SHELL_BuildEnvW    [Internal]
551c2c66affSColin Finck  *
552c2c66affSColin Finck  * Build the environment for the new process, adding the specified
553c2c66affSColin Finck  * path to the PATH variable. Returned pointer must be freed by caller.
554c2c66affSColin Finck  */
SHELL_BuildEnvW(const WCHAR * path)555c2c66affSColin Finck static LPWSTR SHELL_BuildEnvW( const WCHAR *path )
556c2c66affSColin Finck {
55706b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> new_env;
55806b6833cSKatayama Hirofumi MZ     WCHAR *strings, *p, *p2;
559c2c66affSColin Finck     int total = wcslen(path) + 1;
560c2c66affSColin Finck     BOOL got_path = FALSE;
561c2c66affSColin Finck 
562c2c66affSColin Finck     if (!(strings = GetEnvironmentStringsW())) return NULL;
563c2c66affSColin Finck     p = strings;
564c2c66affSColin Finck     while (*p)
565c2c66affSColin Finck     {
566c2c66affSColin Finck         int len = wcslen(p) + 1;
56783be315aSHermès Bélusca-Maïto         if (!_wcsnicmp( p, L"PATH=", 5 )) got_path = TRUE;
568c2c66affSColin Finck         total += len;
569c2c66affSColin Finck         p += len;
570c2c66affSColin Finck     }
571c2c66affSColin Finck     if (!got_path) total += 5;  /* we need to create PATH */
572c2c66affSColin Finck     total++;  /* terminating null */
573c2c66affSColin Finck 
57406b6833cSKatayama Hirofumi MZ     if (!new_env.Allocate(total))
575c2c66affSColin Finck     {
576c2c66affSColin Finck         FreeEnvironmentStringsW(strings);
577c2c66affSColin Finck         return NULL;
578c2c66affSColin Finck     }
579c2c66affSColin Finck     p = strings;
580c2c66affSColin Finck     p2 = new_env;
581c2c66affSColin Finck     while (*p)
582c2c66affSColin Finck     {
583c2c66affSColin Finck         int len = wcslen(p) + 1;
584c2c66affSColin Finck         memcpy(p2, p, len * sizeof(WCHAR));
58583be315aSHermès Bélusca-Maïto         if (!_wcsnicmp( p, L"PATH=", 5 ))
586c2c66affSColin Finck         {
587c2c66affSColin Finck             p2[len - 1] = ';';
588c2c66affSColin Finck             wcscpy( p2 + len, path );
589c2c66affSColin Finck             p2 += wcslen(path) + 1;
590c2c66affSColin Finck         }
591c2c66affSColin Finck         p += len;
592c2c66affSColin Finck         p2 += len;
593c2c66affSColin Finck     }
594c2c66affSColin Finck     if (!got_path)
595c2c66affSColin Finck     {
59683be315aSHermès Bélusca-Maïto         wcscpy(p2, L"PATH=");
597c2c66affSColin Finck         wcscat(p2, path);
598c2c66affSColin Finck         p2 += wcslen(p2) + 1;
599c2c66affSColin Finck     }
600c2c66affSColin Finck     *p2 = 0;
601c2c66affSColin Finck     FreeEnvironmentStringsW(strings);
60206b6833cSKatayama Hirofumi MZ     return new_env.Detach();
603c2c66affSColin Finck }
604c2c66affSColin Finck 
605c2c66affSColin Finck /***********************************************************************
606c2c66affSColin Finck  *           SHELL_TryAppPathW    [Internal]
607c2c66affSColin Finck  *
608c2c66affSColin Finck  * Helper function for SHELL_FindExecutable
609c2c66affSColin Finck  * @param lpResult - pointer to a buffer of size MAX_PATH
610c2c66affSColin Finck  * On entry: szName is a filename (probably without path separators).
611c2c66affSColin Finck  * On exit: if szName found in "App Path", place full path in lpResult, and return true
612c2c66affSColin Finck  */
SHELL_TryAppPathW(LPCWSTR szName,LPWSTR lpResult,WCHAR ** env)613c2c66affSColin Finck static BOOL SHELL_TryAppPathW( LPCWSTR szName, LPWSTR lpResult, WCHAR **env)
614c2c66affSColin Finck {
615140aa11cSKatayama Hirofumi MZ     HKEY hkApp = NULL;
616c2c66affSColin Finck     WCHAR buffer[1024];
617140aa11cSKatayama Hirofumi MZ     DWORD len, dwType;
618c2c66affSColin Finck     LONG res;
619c2c66affSColin Finck     BOOL found = FALSE;
620c2c66affSColin Finck 
621c2c66affSColin Finck     if (env) *env = NULL;
622c2c66affSColin Finck     wcscpy(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
623c2c66affSColin Finck     wcscat(buffer, szName);
624c2c66affSColin Finck     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp);
625c2c66affSColin Finck     if (res)
626c2c66affSColin Finck     {
627c2c66affSColin Finck         // Add ".exe" extension, if extension does not exists
62883be315aSHermès Bélusca-Maïto         if (PathAddExtensionW(buffer, L".exe"))
629c2c66affSColin Finck         {
630c2c66affSColin Finck             res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp);
631c2c66affSColin Finck         }
632c2c66affSColin Finck         if (res) goto end;
633c2c66affSColin Finck     }
634c2c66affSColin Finck 
635c2c66affSColin Finck     len = MAX_PATH * sizeof(WCHAR);
636140aa11cSKatayama Hirofumi MZ     res = SHRegQueryValueExW(hkApp, NULL, NULL, &dwType, (LPBYTE)lpResult, &len);
637140aa11cSKatayama Hirofumi MZ     if (res != ERROR_SUCCESS || dwType != REG_SZ)
638140aa11cSKatayama Hirofumi MZ         goto end;
639140aa11cSKatayama Hirofumi MZ 
640c2c66affSColin Finck     found = TRUE;
641c2c66affSColin Finck 
642c2c66affSColin Finck     if (env)
643c2c66affSColin Finck     {
644140aa11cSKatayama Hirofumi MZ         len = sizeof(buffer);
645140aa11cSKatayama Hirofumi MZ         res = SHRegQueryValueExW(hkApp, L"Path", NULL, &dwType, (LPBYTE)buffer, &len);
646140aa11cSKatayama Hirofumi MZ         if (res == ERROR_SUCCESS && dwType == REG_SZ && buffer[0])
647c2c66affSColin Finck             *env = SHELL_BuildEnvW(buffer);
648c2c66affSColin Finck     }
649c2c66affSColin Finck 
650c2c66affSColin Finck end:
651c2c66affSColin Finck     if (hkApp) RegCloseKey(hkApp);
652c2c66affSColin Finck     return found;
653c2c66affSColin Finck }
654c2c66affSColin Finck 
655c2c66affSColin Finck /*************************************************************************
656c2c66affSColin Finck  *     SHELL_FindExecutableByVerb [Internal]
657c2c66affSColin Finck  *
658c2c66affSColin Finck  * called from SHELL_FindExecutable or SHELL_execute_class
659c2c66affSColin Finck  * in/out:
660c2c66affSColin Finck  *      classname a buffer, big enough, to get the key name to do actually the
661c2c66affSColin Finck  *              command   "WordPad.Document.1\\shell\\open\\command"
662c2c66affSColin Finck  *              passed as "WordPad.Document.1"
663c2c66affSColin Finck  * in:
664c2c66affSColin Finck  *      lpVerb the operation on it (open)
665c2c66affSColin Finck  *      commandlen the size of command buffer (in bytes)
666c2c66affSColin Finck  * out:
667c2c66affSColin Finck  *      command a buffer, to store the command to do the
668c2c66affSColin Finck  *              operation on the file
669c2c66affSColin Finck  *      key a buffer, big enough, to get the key name to do actually the
670c2c66affSColin Finck  *              command "WordPad.Document.1\\shell\\open\\command"
671c2c66affSColin Finck  *              Can be NULL
672c2c66affSColin Finck  */
SHELL_FindExecutableByVerb(LPCWSTR lpVerb,LPWSTR key,LPWSTR classname,LPWSTR command,LONG commandlen)673c2c66affSColin Finck static UINT SHELL_FindExecutableByVerb(LPCWSTR lpVerb, LPWSTR key, LPWSTR classname, LPWSTR command, LONG commandlen)
674c2c66affSColin Finck {
675c2c66affSColin Finck     HKEY hkeyClass;
676c2c66affSColin Finck     WCHAR verb[MAX_PATH];
677c2c66affSColin Finck 
678c2c66affSColin Finck     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, classname, 0, 0x02000000, &hkeyClass))
679c2c66affSColin Finck         return SE_ERR_NOASSOC;
68083be315aSHermès Bélusca-Maïto     if (!HCR_GetDefaultVerbW(hkeyClass, lpVerb, verb, ARRAY_SIZE(verb)))
681c2c66affSColin Finck         return SE_ERR_NOASSOC;
682c2c66affSColin Finck     RegCloseKey(hkeyClass);
683c2c66affSColin Finck 
684c2c66affSColin Finck     /* Looking for ...buffer\shell\<verb>\command */
685c2c66affSColin Finck     wcscat(classname, L"\\shell\\");
686c2c66affSColin Finck     wcscat(classname, verb);
68783be315aSHermès Bélusca-Maïto     wcscat(classname, L"\\command");
688c2c66affSColin Finck 
689c2c66affSColin Finck     if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, command,
690c2c66affSColin Finck                        &commandlen) == ERROR_SUCCESS)
691c2c66affSColin Finck     {
692c2c66affSColin Finck         commandlen /= sizeof(WCHAR);
693c2c66affSColin Finck         if (key) wcscpy(key, classname);
694c2c66affSColin Finck #if 0
695c2c66affSColin Finck         LPWSTR tmp;
696c2c66affSColin Finck         WCHAR param[256];
697c2c66affSColin Finck         LONG paramlen = sizeof(param);
698c2c66affSColin Finck 
699c2c66affSColin Finck         /* FIXME: it seems all Windows version don't behave the same here.
700c2c66affSColin Finck          * the doc states that this ddeexec information can be found after
701c2c66affSColin Finck          * the exec names.
702c2c66affSColin Finck          * on Win98, it doesn't appear, but I think it does on Win2k
703c2c66affSColin Finck          */
704c2c66affSColin Finck         /* Get the parameters needed by the application
705c2c66affSColin Finck            from the associated ddeexec key */
70683be315aSHermès Bélusca-Maïto         tmp = strstrW(classname, L"\\command");
707c2c66affSColin Finck         tmp[0] = '\0';
708c2c66affSColin Finck         wcscat(classname, wDdeexec);
709c2c66affSColin Finck         if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, param,
710c2c66affSColin Finck                            &paramlen) == ERROR_SUCCESS)
711c2c66affSColin Finck         {
712c2c66affSColin Finck             paramlen /= sizeof(WCHAR);
71383be315aSHermès Bélusca-Maïto             wcscat(command, L" ");
714c2c66affSColin Finck             wcscat(command, param);
715c2c66affSColin Finck             commandlen += paramlen;
716c2c66affSColin Finck         }
717c2c66affSColin Finck #endif
718c2c66affSColin Finck 
719c2c66affSColin Finck         command[commandlen] = '\0';
720c2c66affSColin Finck 
721c2c66affSColin Finck         return 33; /* FIXME see SHELL_FindExecutable() */
722c2c66affSColin Finck     }
723c2c66affSColin Finck 
724c2c66affSColin Finck     return SE_ERR_NOASSOC;
725c2c66affSColin Finck }
726c2c66affSColin Finck 
727c2c66affSColin Finck /*************************************************************************
728c2c66affSColin Finck  *    SHELL_FindExecutable [Internal]
729c2c66affSColin Finck  *
730c2c66affSColin Finck  * Utility for code sharing between FindExecutable and ShellExecute
731c2c66affSColin Finck  * in:
732c2c66affSColin Finck  *      lpFile the name of a file
733c2c66affSColin Finck  *      lpVerb the operation on it (open)
734c2c66affSColin Finck  * out:
735c2c66affSColin Finck  *      lpResult a buffer, big enough :-(, to store the command to do the
736c2c66affSColin Finck  *              operation on the file
737c2c66affSColin Finck  *      key a buffer, big enough, to get the key name to do actually the
738c2c66affSColin Finck  *              command (it'll be used afterwards for more information
739c2c66affSColin Finck  *              on the operation)
740c2c66affSColin Finck  */
SHELL_FindExecutable(LPCWSTR lpPath,LPCWSTR lpFile,LPCWSTR lpVerb,LPWSTR lpResult,DWORD resultLen,LPWSTR key,WCHAR ** env,LPITEMIDLIST pidl,LPCWSTR args)741c2c66affSColin Finck static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb,
742c2c66affSColin Finck                                  LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args)
743c2c66affSColin Finck {
744c2c66affSColin Finck     WCHAR *extension = NULL; /* pointer to file extension */
745c2c66affSColin Finck     WCHAR classname[256];     /* registry name for this file type */
746c2c66affSColin Finck     LONG  classnamelen = sizeof(classname); /* length of above */
747c2c66affSColin Finck     WCHAR command[1024];     /* command from registry */
748c2c66affSColin Finck     WCHAR wBuffer[256];      /* Used to GetProfileString */
749c2c66affSColin Finck     UINT  retval = SE_ERR_NOASSOC;
750c2c66affSColin Finck     WCHAR *tok;              /* token pointer */
75142d5dfd3SOleg Dubinskiy     WCHAR xlpFile[MAX_PATH]; /* result of SearchPath */
752c2c66affSColin Finck     DWORD attribs;           /* file attributes */
75342d5dfd3SOleg Dubinskiy     WCHAR curdir[MAX_PATH];
75442d5dfd3SOleg Dubinskiy     const WCHAR *search_paths[3] = {0};
755c2c66affSColin Finck 
756c2c66affSColin Finck     TRACE("%s\n", debugstr_w(lpFile));
757c2c66affSColin Finck 
758c2c66affSColin Finck     if (!lpResult)
759c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
760c2c66affSColin Finck 
761c2c66affSColin Finck     xlpFile[0] = '\0';
762c2c66affSColin Finck     lpResult[0] = '\0'; /* Start off with an empty return string */
763c2c66affSColin Finck     if (key) *key = '\0';
764c2c66affSColin Finck 
765c2c66affSColin Finck     /* trap NULL parameters on entry */
766c2c66affSColin Finck     if (!lpFile)
767c2c66affSColin Finck     {
768c2c66affSColin Finck         WARN("(lpFile=%s,lpResult=%s): NULL parameter\n",
769c2c66affSColin Finck              debugstr_w(lpFile), debugstr_w(lpResult));
770c2c66affSColin Finck         return ERROR_FILE_NOT_FOUND; /* File not found. Close enough, I guess. */
771c2c66affSColin Finck     }
772c2c66affSColin Finck 
773c2c66affSColin Finck     if (SHELL_TryAppPathW( lpFile, lpResult, env ))
774c2c66affSColin Finck     {
775c2c66affSColin Finck         TRACE("found %s via App Paths\n", debugstr_w(lpResult));
776c2c66affSColin Finck         return 33;
777c2c66affSColin Finck     }
778c2c66affSColin Finck 
77942d5dfd3SOleg Dubinskiy     GetCurrentDirectoryW(ARRAY_SIZE(curdir), curdir);
78042d5dfd3SOleg Dubinskiy     if (!PathIsFileSpecW(lpFile))
781c2c66affSColin Finck     {
78242d5dfd3SOleg Dubinskiy         BOOL found = FALSE;
78342d5dfd3SOleg Dubinskiy         if (lpPath && *lpPath)
78442d5dfd3SOleg Dubinskiy         {
78542d5dfd3SOleg Dubinskiy             TRACE("lpPath %s\n", debugstr_w(lpPath));
78642d5dfd3SOleg Dubinskiy             PathCombineW(xlpFile, lpPath, lpFile);
78742d5dfd3SOleg Dubinskiy             if (PathFileExistsDefExtW(xlpFile, WHICH_DEFAULT | WHICH_OPTIONAL) || PathFileExistsW(xlpFile))
78842d5dfd3SOleg Dubinskiy             {
78942d5dfd3SOleg Dubinskiy                 GetFullPathNameW(xlpFile, ARRAY_SIZE(xlpFile), xlpFile, NULL);
79042d5dfd3SOleg Dubinskiy                 found = TRUE;
791c2c66affSColin Finck             }
79242d5dfd3SOleg Dubinskiy         }
79342d5dfd3SOleg Dubinskiy         if (!found)
794c2c66affSColin Finck         {
79542d5dfd3SOleg Dubinskiy             lstrcpyW(xlpFile, lpFile);
79642d5dfd3SOleg Dubinskiy             if (PathFileExistsDefExtW(xlpFile, WHICH_DEFAULT | WHICH_OPTIONAL) || PathFileExistsW(xlpFile))
79742d5dfd3SOleg Dubinskiy             {
79842d5dfd3SOleg Dubinskiy                 GetFullPathNameW(xlpFile, ARRAY_SIZE(xlpFile), xlpFile, NULL);
79942d5dfd3SOleg Dubinskiy                 found = TRUE;
80042d5dfd3SOleg Dubinskiy             }
80142d5dfd3SOleg Dubinskiy         }
80242d5dfd3SOleg Dubinskiy         if (found)
80342d5dfd3SOleg Dubinskiy         {
804c2c66affSColin Finck             lpFile = xlpFile;
80542d5dfd3SOleg Dubinskiy             lstrcpyW(lpResult, xlpFile);
80642d5dfd3SOleg Dubinskiy         }
80742d5dfd3SOleg Dubinskiy         else
80842d5dfd3SOleg Dubinskiy             xlpFile[0] = '\0';
80942d5dfd3SOleg Dubinskiy     }
81042d5dfd3SOleg Dubinskiy     else
81142d5dfd3SOleg Dubinskiy     {
81242d5dfd3SOleg Dubinskiy         if (lpPath && *lpPath)
81342d5dfd3SOleg Dubinskiy         {
81442d5dfd3SOleg Dubinskiy             search_paths[0] = lpPath;
81542d5dfd3SOleg Dubinskiy             search_paths[1] = curdir;
81642d5dfd3SOleg Dubinskiy         }
81742d5dfd3SOleg Dubinskiy         else
81842d5dfd3SOleg Dubinskiy             search_paths[0] = curdir;
81942d5dfd3SOleg Dubinskiy         lstrcpyW(xlpFile, lpFile);
82042d5dfd3SOleg Dubinskiy         if (PathResolveW(xlpFile, search_paths, PRF_TRYPROGRAMEXTENSIONS | PRF_VERIFYEXISTS))
82142d5dfd3SOleg Dubinskiy         {
82242d5dfd3SOleg Dubinskiy             TRACE("PathResolveW returned non-zero\n");
82342d5dfd3SOleg Dubinskiy             lpFile = xlpFile;
82442d5dfd3SOleg Dubinskiy             lstrcpyW(lpResult, xlpFile);
82542d5dfd3SOleg Dubinskiy             /* The file was found in lpPath or one of the directories in the system-wide search path */
82642d5dfd3SOleg Dubinskiy         }
82742d5dfd3SOleg Dubinskiy         else
82842d5dfd3SOleg Dubinskiy             xlpFile[0] = '\0';
829c2c66affSColin Finck     }
830c2c66affSColin Finck 
831c2c66affSColin Finck     attribs = GetFileAttributesW(lpFile);
832c2c66affSColin Finck     if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY))
833c2c66affSColin Finck     {
834c2c66affSColin Finck         wcscpy(classname, L"Folder");
835c2c66affSColin Finck     }
836c2c66affSColin Finck     else
837c2c66affSColin Finck     {
838c2c66affSColin Finck         /* Did we get something? Anything? */
839c2c66affSColin Finck         if (xlpFile[0] == 0)
840c2c66affSColin Finck         {
841c2c66affSColin Finck             TRACE("Returning SE_ERR_FNF\n");
842c2c66affSColin Finck             return SE_ERR_FNF;
843c2c66affSColin Finck         }
844c2c66affSColin Finck         /* First thing we need is the file's extension */
845c2c66affSColin Finck         extension = wcsrchr(xlpFile, '.'); /* Assume last "." is the one; */
846c2c66affSColin Finck         /* File->Run in progman uses */
847c2c66affSColin Finck         /* .\FILE.EXE :( */
848c2c66affSColin Finck         TRACE("xlpFile=%s,extension=%s\n", debugstr_w(xlpFile), debugstr_w(extension));
849c2c66affSColin Finck 
850c2c66affSColin Finck         if (extension == NULL || extension[1] == 0)
851c2c66affSColin Finck         {
852c2c66affSColin Finck             WARN("Returning SE_ERR_NOASSOC\n");
853c2c66affSColin Finck             return SE_ERR_NOASSOC;
854c2c66affSColin Finck         }
855c2c66affSColin Finck 
856c2c66affSColin Finck         /* Three places to check: */
857c2c66affSColin Finck         /* 1. win.ini, [windows], programs (NB no leading '.') */
858c2c66affSColin Finck         /* 2. Registry, HKEY_CLASS_ROOT\<classname>\shell\open\command */
859c2c66affSColin Finck         /* 3. win.ini, [extensions], extension (NB no leading '.' */
860c2c66affSColin Finck         /* All I know of the order is that registry is checked before */
861c2c66affSColin Finck         /* extensions; however, it'd make sense to check the programs */
862c2c66affSColin Finck         /* section first, so that's what happens here. */
863c2c66affSColin Finck 
864c2c66affSColin Finck         /* See if it's a program - if GetProfileString fails, we skip this
865c2c66affSColin Finck          * section. Actually, if GetProfileString fails, we've probably
866c2c66affSColin Finck          * got a lot more to worry about than running a program... */
86783be315aSHermès Bélusca-Maïto         if (GetProfileStringW(L"windows", L"programs", L"exe pif bat cmd com", wBuffer, ARRAY_SIZE(wBuffer)) > 0)
868c2c66affSColin Finck         {
869c2c66affSColin Finck             CharLowerW(wBuffer);
870c2c66affSColin Finck             tok = wBuffer;
871c2c66affSColin Finck             while (*tok)
872c2c66affSColin Finck             {
873c2c66affSColin Finck                 WCHAR *p = tok;
874c2c66affSColin Finck                 while (*p && *p != ' ' && *p != '\t') p++;
875c2c66affSColin Finck                 if (*p)
876c2c66affSColin Finck                 {
877c2c66affSColin Finck                     *p++ = 0;
878c2c66affSColin Finck                     while (*p == ' ' || *p == '\t') p++;
879c2c66affSColin Finck                 }
880c2c66affSColin Finck 
881e4930be4STimo Kreuzer                 if (_wcsicmp(tok, &extension[1]) == 0) /* have to skip the leading "." */
882c2c66affSColin Finck                 {
883c2c66affSColin Finck                     wcscpy(lpResult, xlpFile);
884c2c66affSColin Finck                     /* Need to perhaps check that the file has a path
885c2c66affSColin Finck                      * attached */
886c2c66affSColin Finck                     TRACE("found %s\n", debugstr_w(lpResult));
887c2c66affSColin Finck                     return 33;
888c2c66affSColin Finck                     /* Greater than 32 to indicate success */
889c2c66affSColin Finck                 }
890c2c66affSColin Finck                 tok = p;
891c2c66affSColin Finck             }
892c2c66affSColin Finck         }
893c2c66affSColin Finck 
894c2c66affSColin Finck         /* Check registry */
895c2c66affSColin Finck         if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, classname,
896c2c66affSColin Finck                            &classnamelen) == ERROR_SUCCESS)
897c2c66affSColin Finck         {
898c2c66affSColin Finck             classnamelen /= sizeof(WCHAR);
89983be315aSHermès Bélusca-Maïto             if (classnamelen == ARRAY_SIZE(classname))
900c2c66affSColin Finck                 classnamelen--;
901c2c66affSColin Finck 
902c2c66affSColin Finck             classname[classnamelen] = '\0';
903c2c66affSColin Finck             TRACE("File type: %s\n", debugstr_w(classname));
904c2c66affSColin Finck         }
905c2c66affSColin Finck         else
906c2c66affSColin Finck         {
907c2c66affSColin Finck             *classname = '\0';
908c2c66affSColin Finck         }
909c2c66affSColin Finck     }
910c2c66affSColin Finck 
911c2c66affSColin Finck     if (*classname)
912c2c66affSColin Finck     {
913c2c66affSColin Finck         /* pass the verb string to SHELL_FindExecutableByVerb() */
914c2c66affSColin Finck         retval = SHELL_FindExecutableByVerb(lpVerb, key, classname, command, sizeof(command));
915c2c66affSColin Finck 
916c2c66affSColin Finck         if (retval > 32)
917c2c66affSColin Finck         {
918c2c66affSColin Finck             DWORD finishedLen;
919e018cceaSKatayama Hirofumi MZ             SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen, lpPath);
920c2c66affSColin Finck             if (finishedLen > resultLen)
921c2c66affSColin Finck                 ERR("Argify buffer not large enough.. truncated\n");
922c2c66affSColin Finck             /* Remove double quotation marks and command line arguments */
923c2c66affSColin Finck             if (*lpResult == '"')
924c2c66affSColin Finck             {
925c2c66affSColin Finck                 WCHAR *p = lpResult;
926c2c66affSColin Finck                 while (*(p + 1) != '"')
927c2c66affSColin Finck                 {
928c2c66affSColin Finck                     *p = *(p + 1);
929c2c66affSColin Finck                     p++;
930c2c66affSColin Finck                 }
931c2c66affSColin Finck                 *p = '\0';
932c2c66affSColin Finck             }
933c2c66affSColin Finck             else
934c2c66affSColin Finck             {
935c2c66affSColin Finck                 /* Truncate on first space */
936c2c66affSColin Finck                 WCHAR *p = lpResult;
937c2c66affSColin Finck                 while (*p != ' ' && *p != '\0')
938c2c66affSColin Finck                     p++;
939c2c66affSColin Finck                 *p = '\0';
940c2c66affSColin Finck             }
941c2c66affSColin Finck         }
942c2c66affSColin Finck     }
943c2c66affSColin Finck     else /* Check win.ini */
944c2c66affSColin Finck     {
945c2c66affSColin Finck         /* Toss the leading dot */
946c2c66affSColin Finck         extension++;
94783be315aSHermès Bélusca-Maïto         if (GetProfileStringW(L"extensions", extension, L"", command, ARRAY_SIZE(command)) > 0)
948c2c66affSColin Finck         {
949c2c66affSColin Finck             if (wcslen(command) != 0)
950c2c66affSColin Finck             {
951c2c66affSColin Finck                 wcscpy(lpResult, command);
952c2c66affSColin Finck                 tok = wcschr(lpResult, '^'); /* should be ^.extension? */
953c2c66affSColin Finck                 if (tok != NULL)
954c2c66affSColin Finck                 {
955c2c66affSColin Finck                     tok[0] = '\0';
956c2c66affSColin Finck                     wcscat(lpResult, xlpFile); /* what if no dir in xlpFile? */
957c2c66affSColin Finck                     tok = wcschr(command, '^'); /* see above */
958c2c66affSColin Finck                     if ((tok != NULL) && (wcslen(tok) > 5))
959c2c66affSColin Finck                     {
960c2c66affSColin Finck                         wcscat(lpResult, &tok[5]);
961c2c66affSColin Finck                     }
962c2c66affSColin Finck                 }
963c2c66affSColin Finck                 retval = 33; /* FIXME - see above */
964c2c66affSColin Finck             }
965c2c66affSColin Finck         }
966c2c66affSColin Finck     }
967c2c66affSColin Finck 
96842d5dfd3SOleg Dubinskiy     TRACE("returning path %s, retval %d\n", debugstr_w(lpResult), retval);
969c2c66affSColin Finck     return retval;
970c2c66affSColin Finck }
971c2c66affSColin Finck 
972c2c66affSColin Finck /******************************************************************
973c2c66affSColin Finck  *        dde_cb
974c2c66affSColin Finck  *
975c2c66affSColin Finck  * callback for the DDE connection. not really useful
976c2c66affSColin Finck  */
dde_cb(UINT uType,UINT uFmt,HCONV hConv,HSZ hsz1,HSZ hsz2,HDDEDATA hData,ULONG_PTR dwData1,ULONG_PTR dwData2)977c2c66affSColin Finck static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv,
978c2c66affSColin Finck                                 HSZ hsz1, HSZ hsz2, HDDEDATA hData,
979c2c66affSColin Finck                                 ULONG_PTR dwData1, ULONG_PTR dwData2)
980c2c66affSColin Finck {
981c2c66affSColin Finck     TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
982c2c66affSColin Finck           uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
983c2c66affSColin Finck     return NULL;
984c2c66affSColin Finck }
985c2c66affSColin Finck 
986c2c66affSColin Finck /******************************************************************
987c2c66affSColin Finck  *        dde_connect
988c2c66affSColin Finck  *
989c2c66affSColin Finck  * ShellExecute helper. Used to do an operation with a DDE connection
990c2c66affSColin Finck  *
991c2c66affSColin Finck  * Handles both the direct connection (try #1), and if it fails,
992c2c66affSColin Finck  * launching an application and trying (#2) to connect to it
993c2c66affSColin Finck  *
994c2c66affSColin Finck  */
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)995c2c66affSColin Finck static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec,
996c2c66affSColin Finck                             const WCHAR* lpFile, WCHAR *env,
997c2c66affSColin Finck                             LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc,
998c2c66affSColin Finck                             const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
999c2c66affSColin Finck {
1000c2c66affSColin Finck     WCHAR       regkey[256];
1001c2c66affSColin Finck     WCHAR *     endkey = regkey + wcslen(key);
1002c2c66affSColin Finck     WCHAR       app[256], topic[256], ifexec[256], static_res[256];
100306b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> dynamic_res;
1004c2c66affSColin Finck     WCHAR *     res;
1005c2c66affSColin Finck     LONG        applen, topiclen, ifexeclen;
1006c2c66affSColin Finck     WCHAR *     exec;
1007c2c66affSColin Finck     DWORD       ddeInst = 0;
1008c2c66affSColin Finck     DWORD       tid;
1009c2c66affSColin Finck     DWORD       resultLen, endkeyLen;
1010c2c66affSColin Finck     HSZ         hszApp, hszTopic;
1011c2c66affSColin Finck     HCONV       hConv;
1012c2c66affSColin Finck     HDDEDATA    hDdeData;
1013c2c66affSColin Finck     unsigned    ret = SE_ERR_NOASSOC;
1014c2c66affSColin Finck     BOOL unicode = !(GetVersion() & 0x80000000);
1015c2c66affSColin Finck 
101683be315aSHermès Bélusca-Maïto     if (strlenW(key) + 1 > ARRAY_SIZE(regkey))
1017c2c66affSColin Finck     {
1018c2c66affSColin Finck         FIXME("input parameter %s larger than buffer\n", debugstr_w(key));
1019c2c66affSColin Finck         return 2;
1020c2c66affSColin Finck     }
1021c2c66affSColin Finck     wcscpy(regkey, key);
102283be315aSHermès Bélusca-Maïto     endkeyLen = ARRAY_SIZE(regkey) - (endkey - regkey);
102383be315aSHermès Bélusca-Maïto     if (strlenW(L"\\application") + 1 > endkeyLen)
1024c2c66affSColin Finck     {
102583be315aSHermès Bélusca-Maïto         FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\application"));
1026c2c66affSColin Finck         return 2;
1027c2c66affSColin Finck     }
102883be315aSHermès Bélusca-Maïto     wcscpy(endkey, L"\\application");
1029c2c66affSColin Finck     applen = sizeof(app);
1030c2c66affSColin Finck     if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, app, &applen) != ERROR_SUCCESS)
1031c2c66affSColin Finck     {
1032c2c66affSColin Finck         WCHAR command[1024], fullpath[MAX_PATH];
1033c2c66affSColin Finck         LPWSTR ptr = NULL;
1034c2c66affSColin Finck         DWORD ret = 0;
1035c2c66affSColin Finck 
1036c2c66affSColin Finck         /* Get application command from start string and find filename of application */
1037c2c66affSColin Finck         if (*start == '"')
1038c2c66affSColin Finck         {
103983be315aSHermès Bélusca-Maïto             if (strlenW(start + 1) + 1 > ARRAY_SIZE(command))
1040c2c66affSColin Finck             {
1041c2c66affSColin Finck                 FIXME("size of input parameter %s larger than buffer\n",
1042c2c66affSColin Finck                       debugstr_w(start + 1));
1043c2c66affSColin Finck                 return 2;
1044c2c66affSColin Finck             }
1045c2c66affSColin Finck             wcscpy(command, start + 1);
1046c2c66affSColin Finck             if ((ptr = wcschr(command, '"')))
1047c2c66affSColin Finck                 * ptr = 0;
104883be315aSHermès Bélusca-Maïto             ret = SearchPathW(NULL, command, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr);
1049c2c66affSColin Finck         }
1050c2c66affSColin Finck         else
1051c2c66affSColin Finck         {
1052c2c66affSColin Finck             LPCWSTR p;
1053c2c66affSColin Finck             LPWSTR space;
1054c2c66affSColin Finck             for (p = start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1)
1055c2c66affSColin Finck             {
1056c2c66affSColin Finck                 int idx = space - start;
1057c2c66affSColin Finck                 memcpy(command, start, idx * sizeof(WCHAR));
1058c2c66affSColin Finck                 command[idx] = '\0';
105983be315aSHermès Bélusca-Maïto                 if ((ret = SearchPathW(NULL, command, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr)))
1060c2c66affSColin Finck                     break;
1061c2c66affSColin Finck             }
1062c2c66affSColin Finck             if (!ret)
106383be315aSHermès Bélusca-Maïto                 ret = SearchPathW(NULL, start, L".exe", ARRAY_SIZE(fullpath), fullpath, &ptr);
1064c2c66affSColin Finck         }
1065c2c66affSColin Finck 
1066c2c66affSColin Finck         if (!ret)
1067c2c66affSColin Finck         {
1068c2c66affSColin Finck             ERR("Unable to find application path for command %s\n", debugstr_w(start));
1069c2c66affSColin Finck             return ERROR_ACCESS_DENIED;
1070c2c66affSColin Finck         }
107183be315aSHermès Bélusca-Maïto         if (strlenW(ptr) + 1 > ARRAY_SIZE(app))
1072c2c66affSColin Finck         {
1073c2c66affSColin Finck             FIXME("size of found path %s larger than buffer\n", debugstr_w(ptr));
1074c2c66affSColin Finck             return 2;
1075c2c66affSColin Finck         }
1076c2c66affSColin Finck         wcscpy(app, ptr);
1077c2c66affSColin Finck 
1078c2c66affSColin Finck         /* Remove extensions (including .so) */
107983be315aSHermès Bélusca-Maïto         ptr = app + wcslen(app) - 3;
108083be315aSHermès Bélusca-Maïto         if (ptr > app && !wcscmp(ptr, L".so"))
1081c2c66affSColin Finck             *ptr = 0;
1082c2c66affSColin Finck 
1083c2c66affSColin Finck         ptr = const_cast<LPWSTR>(strrchrW(app, '.'));
1084c2c66affSColin Finck         assert(ptr);
1085c2c66affSColin Finck         *ptr = 0;
1086c2c66affSColin Finck     }
1087c2c66affSColin Finck 
108883be315aSHermès Bélusca-Maïto     if (strlenW(L"\\topic") + 1 > endkeyLen)
1089c2c66affSColin Finck     {
109083be315aSHermès Bélusca-Maïto         FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\topic"));
1091c2c66affSColin Finck         return 2;
1092c2c66affSColin Finck     }
109383be315aSHermès Bélusca-Maïto     wcscpy(endkey, L"\\topic");
1094c2c66affSColin Finck     topiclen = sizeof(topic);
1095c2c66affSColin Finck     if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS)
1096c2c66affSColin Finck     {
1097c2c66affSColin Finck         wcscpy(topic, L"System");
1098c2c66affSColin Finck     }
1099c2c66affSColin Finck 
1100c2c66affSColin Finck     if (unicode)
1101c2c66affSColin Finck     {
1102c2c66affSColin Finck         if (DdeInitializeW(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
1103c2c66affSColin Finck             return 2;
1104c2c66affSColin Finck     }
1105c2c66affSColin Finck     else
1106c2c66affSColin Finck     {
1107c2c66affSColin Finck         if (DdeInitializeA(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
1108c2c66affSColin Finck             return 2;
1109c2c66affSColin Finck     }
1110c2c66affSColin Finck 
1111c2c66affSColin Finck     hszApp = DdeCreateStringHandleW(ddeInst, app, CP_WINUNICODE);
1112c2c66affSColin Finck     hszTopic = DdeCreateStringHandleW(ddeInst, topic, CP_WINUNICODE);
1113c2c66affSColin Finck 
1114c2c66affSColin Finck     hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
1115c2c66affSColin Finck     exec = ddeexec;
1116c2c66affSColin Finck     if (!hConv)
1117c2c66affSColin Finck     {
1118c2c66affSColin Finck         TRACE("Launching %s\n", debugstr_w(start));
1119c2c66affSColin Finck         ret = execfunc(start, env, TRUE, psei, psei_out);
1120c2c66affSColin Finck         if (ret <= 32)
1121c2c66affSColin Finck         {
1122c2c66affSColin Finck             TRACE("Couldn't launch\n");
1123c2c66affSColin Finck             goto error;
1124c2c66affSColin Finck         }
11254e721f78SDoug Lyons         /* if ddeexec is NULL, then we just need to exit here */
11264e721f78SDoug Lyons         if (ddeexec == NULL)
11274e721f78SDoug Lyons         {
11284e721f78SDoug Lyons             TRACE("Exiting because ddeexec is NULL. ret=42.\n");
11294e721f78SDoug Lyons             /* See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew */
11304e721f78SDoug Lyons             /* for reason why we use 42 here and also "Shell32_apitest ShellExecuteW" regression test */
11314e721f78SDoug Lyons             return 42;
11324e721f78SDoug Lyons         }
11334e721f78SDoug Lyons         /* if ddeexec is 'empty string', then we just need to exit here */
11344e721f78SDoug Lyons         if (wcscmp(ddeexec, L"") == 0)
11354e721f78SDoug Lyons         {
11364e721f78SDoug Lyons             TRACE("Exiting because ddeexec is 'empty string'. ret=42.\n");
11374e721f78SDoug Lyons             /* See https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew */
11384e721f78SDoug Lyons             /* for reason why we use 42 here and also "Shell32_apitest ShellExecuteW" regression test */
11394e721f78SDoug Lyons             return 42;
11404e721f78SDoug Lyons         }
1141c2c66affSColin Finck         hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
1142c2c66affSColin Finck         if (!hConv)
1143c2c66affSColin Finck         {
1144c2c66affSColin Finck             TRACE("Couldn't connect. ret=%d\n", ret);
1145c2c66affSColin Finck             DdeUninitialize(ddeInst);
1146c2c66affSColin Finck             SetLastError(ERROR_DDE_FAIL);
1147c2c66affSColin Finck             return 30; /* whatever */
1148c2c66affSColin Finck         }
114983be315aSHermès Bélusca-Maïto         if (strlenW(L"\\ifexec") + 1 > endkeyLen)
1150c2c66affSColin Finck         {
115183be315aSHermès Bélusca-Maïto             FIXME("endkey %s overruns buffer\n", debugstr_w(L"\\ifexec"));
1152c2c66affSColin Finck             return 2;
1153c2c66affSColin Finck         }
115483be315aSHermès Bélusca-Maïto         strcpyW(endkey, L"\\ifexec");
1155c2c66affSColin Finck         ifexeclen = sizeof(ifexec);
1156c2c66affSColin Finck         if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS)
1157c2c66affSColin Finck         {
1158c2c66affSColin Finck             exec = ifexec;
1159c2c66affSColin Finck         }
1160c2c66affSColin Finck     }
1161c2c66affSColin Finck 
116283be315aSHermès Bélusca-Maïto     SHELL_ArgifyW(static_res, ARRAY_SIZE(static_res), exec, lpFile, pidl, szCommandline, &resultLen, NULL);
116383be315aSHermès Bélusca-Maïto     if (resultLen > ARRAY_SIZE(static_res))
1164c2c66affSColin Finck     {
116506b6833cSKatayama Hirofumi MZ         dynamic_res.Allocate(resultLen);
116606b6833cSKatayama Hirofumi MZ         res = dynamic_res;
1167e018cceaSKatayama Hirofumi MZ         SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL, NULL);
1168c2c66affSColin Finck     }
1169c2c66affSColin Finck     else
1170c2c66affSColin Finck         res = static_res;
1171c2c66affSColin Finck     TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res));
1172c2c66affSColin Finck 
1173c2c66affSColin Finck     /* It's documented in the KB 330337 that IE has a bug and returns
1174c2c66affSColin Finck      * error DMLERR_NOTPROCESSED on XTYP_EXECUTE request.
1175c2c66affSColin Finck      */
1176c2c66affSColin Finck     if (unicode)
1177c2c66affSColin Finck         hDdeData = DdeClientTransaction((LPBYTE)res, (strlenW(res) + 1) * sizeof(WCHAR), hConv, 0L, 0, XTYP_EXECUTE, 30000, &tid);
1178c2c66affSColin Finck     else
1179c2c66affSColin Finck     {
1180c2c66affSColin Finck         DWORD lenA = WideCharToMultiByte(CP_ACP, 0, res, -1, NULL, 0, NULL, NULL);
118106b6833cSKatayama Hirofumi MZ         CHeapPtr<char, CLocalAllocator> resA;
118206b6833cSKatayama Hirofumi MZ         resA.Allocate(lenA);
1183c2c66affSColin Finck         WideCharToMultiByte(CP_ACP, 0, res, -1, resA, lenA, NULL, NULL);
118406b6833cSKatayama Hirofumi MZ         hDdeData = DdeClientTransaction( (LPBYTE)(LPSTR)resA, lenA, hConv, 0L, 0,
1185c2c66affSColin Finck                                          XTYP_EXECUTE, 10000, &tid );
1186c2c66affSColin Finck     }
1187c2c66affSColin Finck     if (hDdeData)
1188c2c66affSColin Finck         DdeFreeDataHandle(hDdeData);
1189c2c66affSColin Finck     else
1190c2c66affSColin Finck         WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst));
1191c2c66affSColin Finck     ret = 33;
1192c2c66affSColin Finck 
1193c2c66affSColin Finck     DdeDisconnect(hConv);
1194c2c66affSColin Finck 
1195c2c66affSColin Finck error:
1196c2c66affSColin Finck     DdeUninitialize(ddeInst);
1197c2c66affSColin Finck 
1198c2c66affSColin Finck     return ret;
1199c2c66affSColin Finck }
1200c2c66affSColin Finck 
1201c2c66affSColin Finck /*************************************************************************
1202c2c66affSColin Finck  *    execute_from_key [Internal]
1203c2c66affSColin Finck  */
execute_from_key(LPCWSTR key,LPCWSTR lpFile,WCHAR * env,LPCWSTR szCommandline,LPCWSTR executable_name,SHELL_ExecuteW32 execfunc,LPSHELLEXECUTEINFOW psei,LPSHELLEXECUTEINFOW psei_out)1204c2c66affSColin Finck static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env,
1205c2c66affSColin Finck                                  LPCWSTR szCommandline, LPCWSTR executable_name,
1206c2c66affSColin Finck                                  SHELL_ExecuteW32 execfunc,
1207c2c66affSColin Finck                                  LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out)
1208c2c66affSColin Finck {
1209c2c66affSColin Finck     WCHAR cmd[256], param[1024], ddeexec[256];
1210c2c66affSColin Finck     DWORD cmdlen = sizeof(cmd), ddeexeclen = sizeof(ddeexec);
1211c2c66affSColin Finck     UINT_PTR retval = SE_ERR_NOASSOC;
1212c2c66affSColin Finck     DWORD resultLen;
1213c2c66affSColin Finck     LPWSTR tmp;
1214c2c66affSColin Finck 
1215c2c66affSColin Finck     TRACE("%s %s %s %s %s\n", debugstr_w(key), debugstr_w(lpFile), debugstr_w(env),
1216c2c66affSColin Finck           debugstr_w(szCommandline), debugstr_w(executable_name));
1217c2c66affSColin Finck 
1218c2c66affSColin Finck     cmd[0] = '\0';
1219c2c66affSColin Finck     param[0] = '\0';
1220c2c66affSColin Finck 
1221c2c66affSColin Finck     /* Get the application from the registry */
1222c2c66affSColin Finck     if (RegQueryValueW(HKEY_CLASSES_ROOT, key, cmd, (LONG *)&cmdlen) == ERROR_SUCCESS)
1223c2c66affSColin Finck     {
1224c2c66affSColin Finck         TRACE("got cmd: %s\n", debugstr_w(cmd));
1225c2c66affSColin Finck 
1226c2c66affSColin Finck         /* Is there a replace() function anywhere? */
1227c2c66affSColin Finck         cmdlen /= sizeof(WCHAR);
122883be315aSHermès Bélusca-Maïto         if (cmdlen >= ARRAY_SIZE(cmd))
122983be315aSHermès Bélusca-Maïto             cmdlen = ARRAY_SIZE(cmd) - 1;
1230c2c66affSColin Finck         cmd[cmdlen] = '\0';
123183be315aSHermès Bélusca-Maïto         SHELL_ArgifyW(param, ARRAY_SIZE(param), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen,
1232e018cceaSKatayama Hirofumi MZ                       (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL);
123383be315aSHermès Bélusca-Maïto         if (resultLen > ARRAY_SIZE(param))
1234c2c66affSColin Finck             ERR("Argify buffer not large enough, truncating\n");
1235c2c66affSColin Finck     }
1236c2c66affSColin Finck 
1237c2c66affSColin Finck     /* Get the parameters needed by the application
1238c2c66affSColin Finck        from the associated ddeexec key */
1239c2c66affSColin Finck     tmp = const_cast<LPWSTR>(strstrW(key, L"command"));
1240c2c66affSColin Finck     assert(tmp);
1241c2c66affSColin Finck     wcscpy(tmp, L"ddeexec");
1242c2c66affSColin Finck 
1243c2c66affSColin Finck     if (RegQueryValueW(HKEY_CLASSES_ROOT, key, ddeexec, (LONG *)&ddeexeclen) == ERROR_SUCCESS)
1244c2c66affSColin Finck     {
1245c2c66affSColin Finck         TRACE("Got ddeexec %s => %s\n", debugstr_w(key), debugstr_w(ddeexec));
1246c2c66affSColin Finck         if (!param[0]) strcpyW(param, executable_name);
1247c2c66affSColin Finck         retval = dde_connect(key, param, ddeexec, lpFile, env, szCommandline, (LPITEMIDLIST)psei->lpIDList, execfunc, psei, psei_out);
1248c2c66affSColin Finck     }
1249c2c66affSColin Finck     else if (param[0])
1250c2c66affSColin Finck     {
1251c2c66affSColin Finck         TRACE("executing: %s\n", debugstr_w(param));
1252c2c66affSColin Finck         retval = execfunc(param, env, FALSE, psei, psei_out);
1253c2c66affSColin Finck     }
1254c2c66affSColin Finck     else
1255c2c66affSColin Finck         WARN("Nothing appropriate found for %s\n", debugstr_w(key));
1256c2c66affSColin Finck 
1257c2c66affSColin Finck     return retval;
1258c2c66affSColin Finck }
1259c2c66affSColin Finck 
1260c2c66affSColin Finck /*************************************************************************
1261c2c66affSColin Finck  * FindExecutableA            [SHELL32.@]
1262c2c66affSColin Finck  */
FindExecutableA(LPCSTR lpFile,LPCSTR lpDirectory,LPSTR lpResult)1263c2c66affSColin Finck HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
1264c2c66affSColin Finck {
1265c2c66affSColin Finck     HINSTANCE retval;
1266c2c66affSColin Finck     WCHAR *wFile = NULL, *wDirectory = NULL;
1267c2c66affSColin Finck     WCHAR wResult[MAX_PATH];
1268c2c66affSColin Finck 
1269c2c66affSColin Finck     if (lpFile) __SHCloneStrAtoW(&wFile, lpFile);
1270c2c66affSColin Finck     if (lpDirectory) __SHCloneStrAtoW(&wDirectory, lpDirectory);
1271c2c66affSColin Finck 
1272c2c66affSColin Finck     retval = FindExecutableW(wFile, wDirectory, wResult);
1273c2c66affSColin Finck     WideCharToMultiByte(CP_ACP, 0, wResult, -1, lpResult, MAX_PATH, NULL, NULL);
1274c2c66affSColin Finck     SHFree(wFile);
1275c2c66affSColin Finck     SHFree(wDirectory);
1276c2c66affSColin Finck 
1277c2c66affSColin Finck     TRACE("returning %s\n", lpResult);
1278c2c66affSColin Finck     return retval;
1279c2c66affSColin Finck }
1280c2c66affSColin Finck 
1281c2c66affSColin Finck /*************************************************************************
1282c2c66affSColin Finck  * FindExecutableW            [SHELL32.@]
1283c2c66affSColin Finck  *
1284c2c66affSColin Finck  * This function returns the executable associated with the specified file
1285c2c66affSColin Finck  * for the default verb.
1286c2c66affSColin Finck  *
1287c2c66affSColin Finck  * PARAMS
1288c2c66affSColin Finck  *  lpFile   [I] The file to find the association for. This must refer to
1289c2c66affSColin Finck  *               an existing file otherwise FindExecutable fails and returns
1290c2c66affSColin Finck  *               SE_ERR_FNF.
1291c2c66affSColin Finck  *  lpResult [O] Points to a buffer into which the executable path is
1292c2c66affSColin Finck  *               copied. This parameter must not be NULL otherwise
1293c2c66affSColin Finck  *               FindExecutable() segfaults. The buffer must be of size at
1294c2c66affSColin Finck  *               least MAX_PATH characters.
1295c2c66affSColin Finck  *
1296c2c66affSColin Finck  * RETURNS
1297c2c66affSColin Finck  *  A value greater than 32 on success, less than or equal to 32 otherwise.
1298c2c66affSColin Finck  *  See the SE_ERR_* constants.
1299c2c66affSColin Finck  *
1300c2c66affSColin Finck  * NOTES
1301c2c66affSColin Finck  *  On Windows XP and 2003, FindExecutable() seems to first convert the
1302c2c66affSColin Finck  *  filename into 8.3 format, thus taking into account only the first three
1303c2c66affSColin Finck  *  characters of the extension, and expects to find an association for those.
1304c2c66affSColin Finck  *  However other Windows versions behave sanely.
1305c2c66affSColin Finck  */
FindExecutableW(LPCWSTR lpFile,LPCWSTR lpDirectory,LPWSTR lpResult)1306c2c66affSColin Finck HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
1307c2c66affSColin Finck {
1308f9a55858SKatayama Hirofumi MZ     UINT_PTR retval;
1309f9a55858SKatayama Hirofumi MZ     WCHAR old_dir[MAX_PATH], res[MAX_PATH];
1310f9a55858SKatayama Hirofumi MZ     DWORD cch = _countof(res);
1311f9a55858SKatayama Hirofumi MZ     LPCWSTR dirs[2];
1312c2c66affSColin Finck 
1313c2c66affSColin Finck     TRACE("File %s, Dir %s\n", debugstr_w(lpFile), debugstr_w(lpDirectory));
1314c2c66affSColin Finck 
1315f9a55858SKatayama Hirofumi MZ     *lpResult = UNICODE_NULL;
1316c2c66affSColin Finck 
1317f9a55858SKatayama Hirofumi MZ     GetCurrentDirectoryW(_countof(old_dir), old_dir);
1318f9a55858SKatayama Hirofumi MZ 
1319f9a55858SKatayama Hirofumi MZ     if (lpDirectory && *lpDirectory)
1320c2c66affSColin Finck     {
1321c2c66affSColin Finck         SetCurrentDirectoryW(lpDirectory);
1322f9a55858SKatayama Hirofumi MZ         dirs[0] = lpDirectory;
1323f9a55858SKatayama Hirofumi MZ     }
1324f9a55858SKatayama Hirofumi MZ     else
1325f9a55858SKatayama Hirofumi MZ     {
1326f9a55858SKatayama Hirofumi MZ         dirs[0] = old_dir;
1327f9a55858SKatayama Hirofumi MZ     }
1328f9a55858SKatayama Hirofumi MZ     dirs[1] = NULL;
1329f9a55858SKatayama Hirofumi MZ 
1330f9a55858SKatayama Hirofumi MZ     if (!GetShortPathNameW(lpFile, res, _countof(res)))
1331f9a55858SKatayama Hirofumi MZ         StringCchCopyW(res, _countof(res), lpFile);
1332f9a55858SKatayama Hirofumi MZ 
133384f15b15SKatayama Hirofumi MZ     if (PathResolveW(res, dirs, PRF_TRYPROGRAMEXTENSIONS | PRF_FIRSTDIRDEF))
1334f9a55858SKatayama Hirofumi MZ     {
1335f9a55858SKatayama Hirofumi MZ         // NOTE: The last parameter of this AssocQueryStringW call is "strange" in Windows.
1336f9a55858SKatayama Hirofumi MZ         if (PathIsExeW(res) ||
1337f9a55858SKatayama Hirofumi MZ             SUCCEEDED(AssocQueryStringW(ASSOCF_NONE, ASSOCSTR_EXECUTABLE, res, NULL, res, &cch)))
1338f9a55858SKatayama Hirofumi MZ         {
1339f9a55858SKatayama Hirofumi MZ             StringCchCopyW(lpResult, MAX_PATH, res);
1340f9a55858SKatayama Hirofumi MZ             retval = 42;
1341f9a55858SKatayama Hirofumi MZ         }
1342f9a55858SKatayama Hirofumi MZ         else
1343f9a55858SKatayama Hirofumi MZ         {
1344f9a55858SKatayama Hirofumi MZ             retval = SE_ERR_NOASSOC;
1345f9a55858SKatayama Hirofumi MZ         }
1346f9a55858SKatayama Hirofumi MZ     }
1347f9a55858SKatayama Hirofumi MZ     else
1348f9a55858SKatayama Hirofumi MZ     {
1349f9a55858SKatayama Hirofumi MZ         retval = SE_ERR_FNF;
1350c2c66affSColin Finck     }
1351c2c66affSColin Finck 
1352c2c66affSColin Finck     TRACE("returning %s\n", debugstr_w(lpResult));
1353c2c66affSColin Finck     SetCurrentDirectoryW(old_dir);
1354c2c66affSColin Finck     return (HINSTANCE)retval;
1355c2c66affSColin Finck }
1356c2c66affSColin Finck 
1357c2c66affSColin Finck /* FIXME: is this already implemented somewhere else? */
ShellExecute_GetClassKey(const SHELLEXECUTEINFOW * sei)1358c2c66affSColin Finck static HKEY ShellExecute_GetClassKey(const SHELLEXECUTEINFOW *sei)
1359c2c66affSColin Finck {
1360c2c66affSColin Finck     LPCWSTR ext = NULL, lpClass = NULL;
136106b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> cls;
1362c2c66affSColin Finck     DWORD type = 0, sz = 0;
1363c2c66affSColin Finck     HKEY hkey = 0;
1364c2c66affSColin Finck     LONG r;
1365c2c66affSColin Finck 
1366c2c66affSColin Finck     if (sei->fMask & SEE_MASK_CLASSALL)
1367c2c66affSColin Finck         return sei->hkeyClass;
1368c2c66affSColin Finck 
1369c2c66affSColin Finck     if (sei->fMask & SEE_MASK_CLASSNAME)
1370c2c66affSColin Finck         lpClass = sei->lpClass;
1371c2c66affSColin Finck     else
1372c2c66affSColin Finck     {
1373c2c66affSColin Finck         ext = PathFindExtensionW(sei->lpFile);
1374c2c66affSColin Finck         TRACE("ext = %s\n", debugstr_w(ext));
1375c2c66affSColin Finck         if (!ext)
1376c2c66affSColin Finck             return hkey;
1377c2c66affSColin Finck 
1378c2c66affSColin Finck         r = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey);
1379c2c66affSColin Finck         if (r != ERROR_SUCCESS)
1380c2c66affSColin Finck             return hkey;
1381c2c66affSColin Finck 
1382c2c66affSColin Finck         r = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &sz);
1383c2c66affSColin Finck         if (r == ERROR_SUCCESS && type == REG_SZ)
1384c2c66affSColin Finck         {
1385c2c66affSColin Finck             sz += sizeof (WCHAR);
138606b6833cSKatayama Hirofumi MZ             cls.Allocate(sz / sizeof(WCHAR));
1387c2c66affSColin Finck             cls[0] = 0;
138806b6833cSKatayama Hirofumi MZ             RegQueryValueExW(hkey, NULL, 0, &type, (LPBYTE)(LPWSTR)cls, &sz);
1389c2c66affSColin Finck         }
1390c2c66affSColin Finck 
1391c2c66affSColin Finck         RegCloseKey( hkey );
1392c2c66affSColin Finck         lpClass = cls;
1393c2c66affSColin Finck     }
1394c2c66affSColin Finck 
1395c2c66affSColin Finck     TRACE("class = %s\n", debugstr_w(lpClass));
1396c2c66affSColin Finck 
1397c2c66affSColin Finck     hkey = 0;
1398c2c66affSColin Finck     if (lpClass)
1399c2c66affSColin Finck         RegOpenKeyW( HKEY_CLASSES_ROOT, lpClass, &hkey);
1400c2c66affSColin Finck 
1401c2c66affSColin Finck     return hkey;
1402c2c66affSColin Finck }
1403c2c66affSColin Finck 
shellex_get_dataobj(LPSHELLEXECUTEINFOW sei,CComPtr<IDataObject> & dataObj)1404f6f5490aSMark Jansen static HRESULT shellex_get_dataobj( LPSHELLEXECUTEINFOW sei, CComPtr<IDataObject>& dataObj)
1405c2c66affSColin Finck {
1406f6f5490aSMark Jansen     CComHeapPtr<ITEMIDLIST> allocatedPidl;
1407c2c66affSColin Finck     LPITEMIDLIST pidl = NULL;
1408c2c66affSColin Finck 
1409c2c66affSColin Finck     if (sei->fMask & SEE_MASK_CLASSALL)
1410f6f5490aSMark Jansen     {
1411c2c66affSColin Finck         pidl = (LPITEMIDLIST)sei->lpIDList;
1412f6f5490aSMark Jansen     }
1413c2c66affSColin Finck     else
1414c2c66affSColin Finck     {
1415c2c66affSColin Finck         WCHAR fullpath[MAX_PATH];
1416c2c66affSColin Finck         BOOL ret;
1417c2c66affSColin Finck 
1418c2c66affSColin Finck         fullpath[0] = 0;
1419c2c66affSColin Finck         ret = GetFullPathNameW(sei->lpFile, MAX_PATH, fullpath, NULL);
1420c2c66affSColin Finck         if (!ret)
1421f6f5490aSMark Jansen             return HRESULT_FROM_WIN32(GetLastError());
1422c2c66affSColin Finck 
1423c2c66affSColin Finck         pidl = ILCreateFromPathW(fullpath);
1424f6f5490aSMark Jansen         allocatedPidl.Attach(pidl);
1425c2c66affSColin Finck     }
142628399a21SWhindmar Saksit     return SHELL_GetUIObjectOfAbsoluteItem(NULL, pidl, IID_PPV_ARG(IDataObject, &dataObj));
1427c2c66affSColin Finck }
1428c2c66affSColin Finck 
shellex_run_context_menu_default(IShellExtInit * obj,LPSHELLEXECUTEINFOW sei)1429c2c66affSColin Finck static HRESULT shellex_run_context_menu_default(IShellExtInit *obj,
1430c2c66affSColin Finck         LPSHELLEXECUTEINFOW sei)
1431c2c66affSColin Finck {
1432c2c66affSColin Finck     CComPtr<IContextMenu> cm = NULL;
1433c2c66affSColin Finck     CMINVOKECOMMANDINFOEX ici;
1434c2c66affSColin Finck     MENUITEMINFOW info;
1435c2c66affSColin Finck     WCHAR string[0x80];
1436c2c66affSColin Finck     INT i, n, def = -1;
1437c2c66affSColin Finck     HMENU hmenu = 0;
1438c2c66affSColin Finck     HRESULT r;
1439c2c66affSColin Finck 
1440c2c66affSColin Finck     TRACE("%p %p\n", obj, sei);
1441c2c66affSColin Finck 
1442c2c66affSColin Finck     r = obj->QueryInterface(IID_PPV_ARG(IContextMenu, &cm));
1443c2c66affSColin Finck     if (FAILED(r))
1444c2c66affSColin Finck         return r;
1445c2c66affSColin Finck 
1446c2c66affSColin Finck     hmenu = CreateMenu();
1447c2c66affSColin Finck     if (!hmenu)
1448c2c66affSColin Finck         goto end;
1449c2c66affSColin Finck 
1450c2c66affSColin Finck     /* the number of the last menu added is returned in r */
1451c2c66affSColin Finck     r = cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
1452c2c66affSColin Finck     if (FAILED(r))
1453c2c66affSColin Finck         goto end;
1454c2c66affSColin Finck 
1455c2c66affSColin Finck     n = GetMenuItemCount(hmenu);
1456c2c66affSColin Finck     for (i = 0; i < n; i++)
1457c2c66affSColin Finck     {
1458c2c66affSColin Finck         memset(&info, 0, sizeof(info));
1459c2c66affSColin Finck         info.cbSize = sizeof info;
1460c2c66affSColin Finck         info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
1461c2c66affSColin Finck         info.dwTypeData = string;
1462c2c66affSColin Finck         info.cch = sizeof string;
1463c2c66affSColin Finck         string[0] = 0;
1464c2c66affSColin Finck         GetMenuItemInfoW(hmenu, i, TRUE, &info);
1465c2c66affSColin Finck 
1466c2c66affSColin Finck         TRACE("menu %d %s %08x %08lx %08x %08x\n", i, debugstr_w(string),
1467c2c66affSColin Finck               info.fState, info.dwItemData, info.fType, info.wID);
1468c2c66affSColin Finck         if ((!sei->lpVerb && (info.fState & MFS_DEFAULT)) ||
1469c2c66affSColin Finck             (sei->lpVerb && !lstrcmpiW(sei->lpVerb, string)))
1470c2c66affSColin Finck         {
1471c2c66affSColin Finck             def = i;
1472c2c66affSColin Finck             break;
1473c2c66affSColin Finck         }
1474c2c66affSColin Finck     }
1475c2c66affSColin Finck 
1476c2c66affSColin Finck     r = E_FAIL;
1477c2c66affSColin Finck     if (def == -1)
1478c2c66affSColin Finck         goto end;
1479c2c66affSColin Finck 
1480c2c66affSColin Finck     memset(&ici, 0, sizeof ici);
1481c2c66affSColin Finck     ici.cbSize = sizeof ici;
1482c2c66affSColin Finck     ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI));
1483c2c66affSColin Finck     ici.nShow = sei->nShow;
1484c2c66affSColin Finck     ici.lpVerb = MAKEINTRESOURCEA(def);
1485c2c66affSColin Finck     ici.hwnd = sei->hwnd;
1486c2c66affSColin Finck     ici.lpParametersW = sei->lpParameters;
1487c2c66affSColin Finck 
1488c2c66affSColin Finck     r = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
1489c2c66affSColin Finck 
1490c2c66affSColin Finck     TRACE("invoke command returned %08x\n", r);
1491c2c66affSColin Finck 
1492c2c66affSColin Finck end:
1493c2c66affSColin Finck     if (hmenu)
1494c2c66affSColin Finck         DestroyMenu( hmenu );
1495c2c66affSColin Finck     return r;
1496c2c66affSColin Finck }
1497c2c66affSColin Finck 
shellex_load_object_and_run(HKEY hkey,LPCGUID guid,LPSHELLEXECUTEINFOW sei)1498c2c66affSColin Finck static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei)
1499c2c66affSColin Finck {
1500c2c66affSColin Finck     TRACE("%p %s %p\n", hkey, debugstr_guid(guid), sei);
1501c2c66affSColin Finck 
1502f6f5490aSMark Jansen     CCoInit coInit;
1503c2c66affSColin Finck 
1504d82185f1SMark Jansen     if (FAILED_UNEXPECTEDLY(coInit.hr))
1505d82185f1SMark Jansen         return coInit.hr;
1506f6f5490aSMark Jansen 
1507f6f5490aSMark Jansen     CComPtr<IShellExtInit> obj;
1508f6f5490aSMark Jansen     HRESULT hr = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER,
1509c2c66affSColin Finck                          IID_PPV_ARG(IShellExtInit, &obj));
1510f6f5490aSMark Jansen     if (FAILED_UNEXPECTEDLY(hr))
1511f6f5490aSMark Jansen         return hr;
1512c2c66affSColin Finck 
1513f6f5490aSMark Jansen     CComPtr<IDataObject> dataobj;
1514f6f5490aSMark Jansen     hr = shellex_get_dataobj(sei, dataobj);
1515f6f5490aSMark Jansen     if (FAILED_UNEXPECTEDLY(hr))
1516f6f5490aSMark Jansen         return hr;
1517c2c66affSColin Finck 
1518f6f5490aSMark Jansen     hr = obj->Initialize(NULL, dataobj, hkey);
1519f6f5490aSMark Jansen     if (FAILED_UNEXPECTEDLY(hr))
1520f6f5490aSMark Jansen         return hr;
1521c2c66affSColin Finck 
1522f6f5490aSMark Jansen     CComPtr<IObjectWithSite> ows;
1523f6f5490aSMark Jansen     hr = obj->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows));
1524f6f5490aSMark Jansen     if (FAILED_UNEXPECTEDLY(hr))
1525f6f5490aSMark Jansen         return hr;
1526c2c66affSColin Finck 
1527c2c66affSColin Finck     ows->SetSite(NULL);
1528c2c66affSColin Finck 
1529f6f5490aSMark Jansen     return shellex_run_context_menu_default(obj, sei);
1530c2c66affSColin Finck }
1531c2c66affSColin Finck 
shellex_get_contextmenu(LPSHELLEXECUTEINFOW sei,CComPtr<IContextMenu> & cm)1532f6f5490aSMark Jansen static HRESULT shellex_get_contextmenu(LPSHELLEXECUTEINFOW sei, CComPtr<IContextMenu>& cm)
1533f6f5490aSMark Jansen {
1534f6f5490aSMark Jansen     CComHeapPtr<ITEMIDLIST> allocatedPidl;
1535f6f5490aSMark Jansen     LPITEMIDLIST pidl = NULL;
1536f6f5490aSMark Jansen 
1537f6f5490aSMark Jansen     if (sei->lpIDList)
1538f6f5490aSMark Jansen     {
1539f6f5490aSMark Jansen         pidl = (LPITEMIDLIST)sei->lpIDList;
1540f6f5490aSMark Jansen     }
1541f6f5490aSMark Jansen     else
1542f6f5490aSMark Jansen     {
1543f6f5490aSMark Jansen         SFGAOF sfga = 0;
1544f6f5490aSMark Jansen         HRESULT hr = SHParseDisplayName(sei->lpFile, NULL, &allocatedPidl, SFGAO_STORAGECAPMASK, &sfga);
1545f6f5490aSMark Jansen         if (FAILED(hr))
154693fac553SMark Jansen         {
154793fac553SMark Jansen             WCHAR Buffer[MAX_PATH] = {};
154893fac553SMark Jansen             // FIXME: MAX_PATH.....
154993fac553SMark Jansen             UINT retval = SHELL_FindExecutable(sei->lpDirectory, sei->lpFile, sei->lpVerb, Buffer, _countof(Buffer), NULL, NULL, NULL, sei->lpParameters);
155093fac553SMark Jansen             if (retval <= 32)
155193fac553SMark Jansen                 return HRESULT_FROM_WIN32(retval);
155293fac553SMark Jansen 
155393fac553SMark Jansen             hr = SHParseDisplayName(Buffer, NULL, &allocatedPidl, SFGAO_STORAGECAPMASK, &sfga);
155493fac553SMark Jansen             // This should not happen, we found it...
155593fac553SMark Jansen             if (FAILED_UNEXPECTEDLY(hr))
1556f6f5490aSMark Jansen                 return hr;
155793fac553SMark Jansen         }
1558f6f5490aSMark Jansen 
1559f6f5490aSMark Jansen         pidl = allocatedPidl;
1560f6f5490aSMark Jansen     }
1561f6f5490aSMark Jansen 
1562f6f5490aSMark Jansen     CComPtr<IShellFolder> shf;
1563f6f5490aSMark Jansen     LPCITEMIDLIST pidllast = NULL;
1564f6f5490aSMark Jansen     HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast);
1565f6f5490aSMark Jansen     if (FAILED(hr))
1566f6f5490aSMark Jansen         return hr;
1567f6f5490aSMark Jansen 
1568f6f5490aSMark Jansen     return shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IContextMenu, &cm));
1569f6f5490aSMark Jansen }
1570f6f5490aSMark Jansen 
ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)1571ce306b83SMark Jansen static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei)
1572f6f5490aSMark Jansen {
1573f6f5490aSMark Jansen     TRACE("%p\n", sei);
1574f6f5490aSMark Jansen 
1575f6f5490aSMark Jansen     CCoInit coInit;
1576f6f5490aSMark Jansen 
1577d82185f1SMark Jansen     if (FAILED_UNEXPECTEDLY(coInit.hr))
1578d82185f1SMark Jansen         return coInit.hr;
1579f6f5490aSMark Jansen 
1580f6f5490aSMark Jansen     CComPtr<IContextMenu> cm;
1581f6f5490aSMark Jansen     HRESULT hr = shellex_get_contextmenu(sei, cm);
1582f6f5490aSMark Jansen     if (FAILED_UNEXPECTEDLY(hr))
1583f6f5490aSMark Jansen         return hr;
1584f6f5490aSMark Jansen 
1585a5099417SWhindmar Saksit     CComHeapPtr<char> verb, parameters, dir;
1586f6f5490aSMark Jansen     __SHCloneStrWtoA(&verb, sei->lpVerb);
1587f6f5490aSMark Jansen     __SHCloneStrWtoA(&parameters, sei->lpParameters);
1588a5099417SWhindmar Saksit     __SHCloneStrWtoA(&dir, sei->lpDirectory);
1589f6f5490aSMark Jansen 
1590724b20d4SWhindmar Saksit     BOOL fDefault = StrIsNullOrEmpty(sei->lpVerb);
1591f6a25d48SWhindmar Saksit     CMINVOKECOMMANDINFOEX ici = { sizeof(ici) };
1592724b20d4SWhindmar Saksit     ici.fMask = SeeFlagsToCmicFlags(sei->fMask) | CMIC_MASK_UNICODE;
1593f6f5490aSMark Jansen     ici.nShow = sei->nShow;
1594f6a25d48SWhindmar Saksit     if (!fDefault)
1595f6a25d48SWhindmar Saksit     {
1596f6f5490aSMark Jansen         ici.lpVerb = verb;
1597f6a25d48SWhindmar Saksit         ici.lpVerbW = sei->lpVerb;
1598f6a25d48SWhindmar Saksit     }
1599f6f5490aSMark Jansen     ici.hwnd = sei->hwnd;
1600f6f5490aSMark Jansen     ici.lpParameters = parameters;
1601f6a25d48SWhindmar Saksit     ici.lpParametersW = sei->lpParameters;
1602a5099417SWhindmar Saksit     ici.lpDirectory = dir;
1603a5099417SWhindmar Saksit     ici.lpDirectoryW = sei->lpDirectory;
1604724b20d4SWhindmar Saksit     ici.dwHotKey = sei->dwHotKey;
1605724b20d4SWhindmar Saksit     ici.hIcon = sei->hIcon;
1606724b20d4SWhindmar Saksit     if (ici.fMask & (CMIC_MASK_HASLINKNAME | CMIC_MASK_HASTITLE))
1607f6a25d48SWhindmar Saksit         ici.lpTitleW = sei->lpClass;
1608f6f5490aSMark Jansen 
1609724b20d4SWhindmar Saksit     enum { idFirst = 1, idLast = 0x7fff };
1610f6f5490aSMark Jansen     HMENU hMenu = CreatePopupMenu();
161128399a21SWhindmar Saksit     // Note: Windows does not pass CMF_EXTENDEDVERBS so "hidden" verbs cannot be executed
1612724b20d4SWhindmar Saksit     hr = cm->QueryContextMenu(hMenu, 0, idFirst, idLast, fDefault ? CMF_DEFAULTONLY : 0);
1613f6f5490aSMark Jansen     if (!FAILED_UNEXPECTEDLY(hr))
1614f6f5490aSMark Jansen     {
1615f6f5490aSMark Jansen         if (fDefault)
1616f6f5490aSMark Jansen         {
1617f6f5490aSMark Jansen             INT uDefault = GetMenuDefaultItem(hMenu, FALSE, 0);
1618724b20d4SWhindmar Saksit             uDefault = (uDefault != -1) ? uDefault - idFirst : 0;
1619f6f5490aSMark Jansen             ici.lpVerb = MAKEINTRESOURCEA(uDefault);
1620f6a25d48SWhindmar Saksit             ici.lpVerbW = MAKEINTRESOURCEW(uDefault);
1621f6f5490aSMark Jansen         }
1622f6f5490aSMark Jansen 
1623f6f5490aSMark Jansen         hr = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
1624f6f5490aSMark Jansen         if (!FAILED_UNEXPECTEDLY(hr))
1625f6f5490aSMark Jansen             hr = S_OK;
1626f6f5490aSMark Jansen     }
1627f6f5490aSMark Jansen 
1628f6f5490aSMark Jansen     DestroyMenu(hMenu);
1629f6f5490aSMark Jansen 
1630f6f5490aSMark Jansen     return hr;
1631f6f5490aSMark Jansen }
1632f6f5490aSMark Jansen 
1633f6f5490aSMark Jansen 
1634c2c66affSColin Finck /*************************************************************************
1635c2c66affSColin Finck  *    ShellExecute_FromContextMenu [Internal]
1636c2c66affSColin Finck  */
ShellExecute_FromContextMenuHandlers(LPSHELLEXECUTEINFOW sei)1637ce306b83SMark Jansen static LONG ShellExecute_FromContextMenuHandlers( LPSHELLEXECUTEINFOW sei )
1638c2c66affSColin Finck {
1639c2c66affSColin Finck     HKEY hkey, hkeycm = 0;
1640c2c66affSColin Finck     WCHAR szguid[39];
1641c2c66affSColin Finck     HRESULT hr;
1642c2c66affSColin Finck     GUID guid;
1643c2c66affSColin Finck     DWORD i;
1644c2c66affSColin Finck     LONG r;
1645c2c66affSColin Finck 
1646c2c66affSColin Finck     TRACE("%s\n", debugstr_w(sei->lpFile));
1647c2c66affSColin Finck 
1648c2c66affSColin Finck     hkey = ShellExecute_GetClassKey(sei);
1649c2c66affSColin Finck     if (!hkey)
1650c2c66affSColin Finck         return ERROR_FUNCTION_FAILED;
1651c2c66affSColin Finck 
1652c2c66affSColin Finck     r = RegOpenKeyW(hkey, L"shellex\\ContextMenuHandlers", &hkeycm);
1653c2c66affSColin Finck     if (r == ERROR_SUCCESS)
1654c2c66affSColin Finck     {
1655c2c66affSColin Finck         i = 0;
1656c2c66affSColin Finck         while (1)
1657c2c66affSColin Finck         {
165883be315aSHermès Bélusca-Maïto             r = RegEnumKeyW(hkeycm, i++, szguid, ARRAY_SIZE(szguid));
1659c2c66affSColin Finck             if (r != ERROR_SUCCESS)
1660c2c66affSColin Finck                 break;
1661c2c66affSColin Finck 
1662c2c66affSColin Finck             hr = CLSIDFromString(szguid, &guid);
1663c2c66affSColin Finck             if (SUCCEEDED(hr))
1664c2c66affSColin Finck             {
1665c2c66affSColin Finck                 /* stop at the first one that succeeds in running */
1666c2c66affSColin Finck                 hr = shellex_load_object_and_run(hkey, &guid, sei);
1667c2c66affSColin Finck                 if (SUCCEEDED(hr))
1668c2c66affSColin Finck                     break;
1669c2c66affSColin Finck             }
1670c2c66affSColin Finck         }
1671c2c66affSColin Finck         RegCloseKey(hkeycm);
1672c2c66affSColin Finck     }
1673c2c66affSColin Finck 
1674c2c66affSColin Finck     if (hkey != sei->hkeyClass)
1675c2c66affSColin Finck         RegCloseKey(hkey);
1676c2c66affSColin Finck     return r;
1677c2c66affSColin Finck }
1678c2c66affSColin Finck 
1679c2c66affSColin Finck static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR lpstrProtocol, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc);
1680c2c66affSColin Finck 
SHELL_execute_class(LPCWSTR wszApplicationName,LPSHELLEXECUTEINFOW psei,LPSHELLEXECUTEINFOW psei_out,SHELL_ExecuteW32 execfunc)1681c2c66affSColin Finck static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
1682c2c66affSColin Finck {
1683c2c66affSColin Finck     WCHAR execCmd[1024], classname[1024];
1684c2c66affSColin Finck     /* launch a document by fileclass like 'WordPad.Document.1' */
1685c2c66affSColin Finck     /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
1686c2c66affSColin Finck     /* FIXME: wcmd should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */
1687c2c66affSColin Finck     ULONG cmask = (psei->fMask & SEE_MASK_CLASSALL);
1688c2c66affSColin Finck     DWORD resultLen;
1689c2c66affSColin Finck     BOOL done;
1690c2c66affSColin Finck     UINT_PTR rslt;
1691c2c66affSColin Finck 
1692c2c66affSColin Finck     /* FIXME: remove following block when SHELL_quote_and_execute supports hkeyClass parameter */
1693c2c66affSColin Finck     if (cmask != SEE_MASK_CLASSNAME)
1694c2c66affSColin Finck     {
1695c2c66affSColin Finck         WCHAR wcmd[1024];
1696c2c66affSColin Finck         HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL,
1697c2c66affSColin Finck                                (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL,
1698c2c66affSColin Finck                                psei->lpVerb,
1699c2c66affSColin Finck                                execCmd, sizeof(execCmd));
1700c2c66affSColin Finck 
1701c2c66affSColin Finck         /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
1702c2c66affSColin Finck         TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
1703c2c66affSColin Finck 
1704c2c66affSColin Finck         wcmd[0] = '\0';
1705d5aca440SWhindmar Saksit         done = SHELL_ArgifyW(wcmd, ARRAY_SIZE(wcmd), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, psei->lpParameters,
1706d5aca440SWhindmar Saksit                              &resultLen, (psei->lpDirectory && *psei->lpDirectory) ? psei->lpDirectory : NULL);
1707c2c66affSColin Finck         if (!done && wszApplicationName[0])
1708c2c66affSColin Finck         {
1709724b20d4SWhindmar Saksit #if 0       // Given HKCR\.test=SZ:"test" and HKCR\test\shell\open\command=SZ:"cmd.exe /K echo.Hello", no filename is
1710724b20d4SWhindmar Saksit             // appended on Windows when there is no %1 nor %L when executed with: shlextdbg.exe /shellexec=c:\file.test /INVOKE
1711c2c66affSColin Finck             strcatW(wcmd, L" ");
1712c2c66affSColin Finck             if (*wszApplicationName != '"')
1713c2c66affSColin Finck             {
1714c2c66affSColin Finck                 strcatW(wcmd, L"\"");
1715c2c66affSColin Finck                 strcatW(wcmd, wszApplicationName);
1716c2c66affSColin Finck                 strcatW(wcmd, L"\"");
1717c2c66affSColin Finck             }
1718c2c66affSColin Finck             else
1719c2c66affSColin Finck                 strcatW(wcmd, wszApplicationName);
1720724b20d4SWhindmar Saksit #endif
1721c2c66affSColin Finck         }
172283be315aSHermès Bélusca-Maïto         if (resultLen > ARRAY_SIZE(wcmd))
1723c2c66affSColin Finck             ERR("Argify buffer not large enough... truncating\n");
1724c2c66affSColin Finck         return execfunc(wcmd, NULL, FALSE, psei, psei_out);
1725c2c66affSColin Finck     }
1726c2c66affSColin Finck 
1727c2c66affSColin Finck     strcpyW(classname, psei->lpClass);
1728c2c66affSColin Finck     rslt = SHELL_FindExecutableByVerb(psei->lpVerb, NULL, classname, execCmd, sizeof(execCmd));
1729c2c66affSColin Finck 
1730c2c66affSColin Finck     TRACE("SHELL_FindExecutableByVerb returned %u (%s, %s)\n", (unsigned int)rslt, debugstr_w(classname), debugstr_w(execCmd));
1731c2c66affSColin Finck     if (33 > rslt)
1732c2c66affSColin Finck         return rslt;
1733c2c66affSColin Finck     rslt = SHELL_quote_and_execute( execCmd, L"", classname,
1734c2c66affSColin Finck                                       wszApplicationName, NULL, psei,
1735c2c66affSColin Finck                                       psei_out, execfunc );
1736c2c66affSColin Finck     return rslt;
1737c2c66affSColin Finck 
1738c2c66affSColin Finck }
1739c2c66affSColin Finck 
SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei,LPWSTR wszParameters,DWORD parametersLen,LPWSTR wszApplicationName,DWORD dwApplicationNameLen)1740c2c66affSColin Finck static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen)
1741c2c66affSColin Finck {
1742c2c66affSColin Finck     WCHAR buffer[MAX_PATH];
1743c2c66affSColin Finck     BOOL appKnownSingular = FALSE;
1744c2c66affSColin Finck 
1745c2c66affSColin Finck     /* last chance to translate IDList: now also allow CLSID paths */
174683be315aSHermès Bélusca-Maïto     if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, ARRAY_SIZE(buffer)))) {
1747c2c66affSColin Finck         if (buffer[0] == ':' && buffer[1] == ':') {
1748c2c66affSColin Finck             /* open shell folder for the specified class GUID */
1749c2c66affSColin Finck             if (strlenW(buffer) + 1 > parametersLen)
1750c2c66affSColin Finck                 ERR("parameters len exceeds buffer size (%i > %i), truncating\n",
1751c2c66affSColin Finck                     lstrlenW(buffer) + 1, parametersLen);
1752c2c66affSColin Finck             lstrcpynW(wszParameters, buffer, parametersLen);
175383be315aSHermès Bélusca-Maïto             if (strlenW(L"explorer.exe") > dwApplicationNameLen)
175483be315aSHermès Bélusca-Maïto                 ERR("application len exceeds buffer size (%i), truncating\n",
175583be315aSHermès Bélusca-Maïto                     dwApplicationNameLen);
175683be315aSHermès Bélusca-Maïto             lstrcpynW(wszApplicationName, L"explorer.exe", dwApplicationNameLen);
1757c2c66affSColin Finck             appKnownSingular = TRUE;
1758c2c66affSColin Finck 
1759c2c66affSColin Finck             sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
1760c2c66affSColin Finck         } else {
1761ea87f910SWhindmar Saksit             WCHAR target[max(MAX_PATH, _countof(buffer))];
1762c2c66affSColin Finck             DWORD attribs;
1763c2c66affSColin Finck             DWORD resultLen;
1764c2c66affSColin Finck             /* Check if we're executing a directory and if so use the
1765c2c66affSColin Finck                handler for the Folder class */
1766c2c66affSColin Finck             strcpyW(target, buffer);
1767c2c66affSColin Finck             attribs = GetFileAttributesW(buffer);
1768c2c66affSColin Finck             if (attribs != INVALID_FILE_ATTRIBUTES &&
1769c2c66affSColin Finck                     (attribs & FILE_ATTRIBUTE_DIRECTORY) &&
1770c2c66affSColin Finck                     HCR_GetExecuteCommandW(0, L"Folder",
1771c2c66affSColin Finck                                            sei->lpVerb,
1772c2c66affSColin Finck                                            buffer, sizeof(buffer))) {
1773c2c66affSColin Finck                 SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
1774e018cceaSKatayama Hirofumi MZ                               buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen,
1775ea87f910SWhindmar Saksit                               !StrIsNullOrEmpty(sei->lpDirectory) ? sei->lpDirectory : NULL);
1776c2c66affSColin Finck                 if (resultLen > dwApplicationNameLen)
1777ea87f910SWhindmar Saksit                     ERR("Argify buffer not large enough... truncating\n"); // FIXME: Report this to the caller?
1778c2c66affSColin Finck                 appKnownSingular = FALSE;
1779ea87f910SWhindmar Saksit                 // HACKFIX: We really want the !appKnownSingular code in SHELL_execute to split the
1780ea87f910SWhindmar Saksit                 // parameters for us but we cannot guarantee that the exe in the registry is quoted.
1781ea87f910SWhindmar Saksit                 // We have now turned 'explorer.exe "%1" into 'explorer.exe "c:\path\from\pidl"' and
1782ea87f910SWhindmar Saksit                 // need to split to application and parameters.
1783ea87f910SWhindmar Saksit                 LPCWSTR params = PathGetArgsW(wszApplicationName);
1784ea87f910SWhindmar Saksit                 lstrcpynW(wszParameters, params, parametersLen);
1785ea87f910SWhindmar Saksit                 PathRemoveArgsW(wszApplicationName);
1786ea87f910SWhindmar Saksit                 PathUnquoteSpacesW(wszApplicationName);
1787ea87f910SWhindmar Saksit                 appKnownSingular = TRUE;
1788c2c66affSColin Finck             }
1789c2c66affSColin Finck             sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
1790c2c66affSColin Finck         }
1791c2c66affSColin Finck     }
1792c2c66affSColin Finck     return appKnownSingular;
1793c2c66affSColin Finck }
1794c2c66affSColin Finck 
17956f277e97SKatayama Hirofumi MZ static BOOL
SHELL_InvokePidl(_In_ LPSHELLEXECUTEINFOW sei,_In_ LPCITEMIDLIST pidl)17966f277e97SKatayama Hirofumi MZ SHELL_InvokePidl(
17976f277e97SKatayama Hirofumi MZ     _In_ LPSHELLEXECUTEINFOW sei,
17986f277e97SKatayama Hirofumi MZ     _In_ LPCITEMIDLIST pidl)
17996f277e97SKatayama Hirofumi MZ {
18006f277e97SKatayama Hirofumi MZ     // Bind pidl
18016f277e97SKatayama Hirofumi MZ     CComPtr<IShellFolder> psfFolder;
18026f277e97SKatayama Hirofumi MZ     LPCITEMIDLIST pidlLast;
18036f277e97SKatayama Hirofumi MZ     HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psfFolder), &pidlLast);
18046f277e97SKatayama Hirofumi MZ     if (FAILED_UNEXPECTEDLY(hr))
18056f277e97SKatayama Hirofumi MZ         return FALSE;
18066f277e97SKatayama Hirofumi MZ 
18076f277e97SKatayama Hirofumi MZ     // Get the context menu to invoke a command
18086f277e97SKatayama Hirofumi MZ     CComPtr<IContextMenu> pCM;
18096f277e97SKatayama Hirofumi MZ     hr = psfFolder->GetUIObjectOf(NULL, 1, &pidlLast, IID_NULL_PPV_ARG(IContextMenu, &pCM));
18106f277e97SKatayama Hirofumi MZ     if (FAILED_UNEXPECTEDLY(hr))
18116f277e97SKatayama Hirofumi MZ         return FALSE;
18126f277e97SKatayama Hirofumi MZ 
18136f277e97SKatayama Hirofumi MZ     // Invoke a command
18146f277e97SKatayama Hirofumi MZ     CMINVOKECOMMANDINFO ici = { sizeof(ici) };
18156f277e97SKatayama Hirofumi MZ     ici.fMask = (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI));
18166f277e97SKatayama Hirofumi MZ     ici.nShow = sei->nShow;
18176f277e97SKatayama Hirofumi MZ     ici.hwnd = sei->hwnd;
18186f277e97SKatayama Hirofumi MZ     char szVerb[VERBKEY_CCHMAX];
18196f277e97SKatayama Hirofumi MZ     if (sei->lpVerb && sei->lpVerb[0])
18206f277e97SKatayama Hirofumi MZ     {
18216f277e97SKatayama Hirofumi MZ         WideCharToMultiByte(CP_ACP, 0, sei->lpVerb, -1, szVerb, _countof(szVerb), NULL, NULL);
18226f277e97SKatayama Hirofumi MZ         szVerb[_countof(szVerb) - 1] = ANSI_NULL; // Avoid buffer overrun
18236f277e97SKatayama Hirofumi MZ         ici.lpVerb = szVerb;
18246f277e97SKatayama Hirofumi MZ     }
18256f277e97SKatayama Hirofumi MZ     else // The default verb?
18266f277e97SKatayama Hirofumi MZ     {
18276f277e97SKatayama Hirofumi MZ         HMENU hMenu = CreatePopupMenu();
18286f277e97SKatayama Hirofumi MZ         const INT idCmdFirst = 1, idCmdLast = 0x7FFF;
18296f277e97SKatayama Hirofumi MZ         hr = pCM->QueryContextMenu(hMenu, 0, idCmdFirst, idCmdLast, CMF_DEFAULTONLY);
18306f277e97SKatayama Hirofumi MZ         if (FAILED_UNEXPECTEDLY(hr))
18316f277e97SKatayama Hirofumi MZ         {
18326f277e97SKatayama Hirofumi MZ             DestroyMenu(hMenu);
18336f277e97SKatayama Hirofumi MZ             return FALSE;
18346f277e97SKatayama Hirofumi MZ         }
18356f277e97SKatayama Hirofumi MZ 
18366f277e97SKatayama Hirofumi MZ         INT nDefaultID = GetMenuDefaultItem(hMenu, FALSE, 0);
18376f277e97SKatayama Hirofumi MZ         DestroyMenu(hMenu);
18386f277e97SKatayama Hirofumi MZ         if (nDefaultID == -1)
18396f277e97SKatayama Hirofumi MZ             nDefaultID = idCmdFirst;
18406f277e97SKatayama Hirofumi MZ 
18416f277e97SKatayama Hirofumi MZ         ici.lpVerb = MAKEINTRESOURCEA(nDefaultID - idCmdFirst);
18426f277e97SKatayama Hirofumi MZ     }
18436f277e97SKatayama Hirofumi MZ     hr = pCM->InvokeCommand(&ici);
18446f277e97SKatayama Hirofumi MZ 
18456f277e97SKatayama Hirofumi MZ     return !FAILED_UNEXPECTEDLY(hr);
18466f277e97SKatayama Hirofumi MZ }
18476f277e97SKatayama Hirofumi MZ 
SHELL_quote_and_execute(LPCWSTR wcmd,LPCWSTR wszParameters,LPCWSTR wszKeyname,LPCWSTR wszApplicationName,LPWSTR env,LPSHELLEXECUTEINFOW psei,LPSHELLEXECUTEINFOW psei_out,SHELL_ExecuteW32 execfunc)1848c2c66affSColin Finck 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)
1849c2c66affSColin Finck {
1850c2c66affSColin Finck     UINT_PTR retval;
1851c2c66affSColin Finck     DWORD len;
185206b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> wszQuotedCmd;
1853c2c66affSColin Finck 
1854c2c66affSColin Finck     /* Length of quotes plus length of command plus NULL terminator */
1855c2c66affSColin Finck     len = 2 + lstrlenW(wcmd) + 1;
1856c2c66affSColin Finck     if (wszParameters[0])
1857c2c66affSColin Finck     {
1858c2c66affSColin Finck         /* Length of space plus length of parameters */
1859c2c66affSColin Finck         len += 1 + lstrlenW(wszParameters);
1860c2c66affSColin Finck     }
186106b6833cSKatayama Hirofumi MZ     wszQuotedCmd.Allocate(len);
1862c2c66affSColin Finck     /* Must quote to handle case where cmd contains spaces,
1863c2c66affSColin Finck      * else security hole if malicious user creates executable file "C:\\Program"
1864c2c66affSColin Finck      */
1865c2c66affSColin Finck     strcpyW(wszQuotedCmd, L"\"");
1866c2c66affSColin Finck     strcatW(wszQuotedCmd, wcmd);
1867c2c66affSColin Finck     strcatW(wszQuotedCmd, L"\"");
1868c2c66affSColin Finck     if (wszParameters[0])
1869c2c66affSColin Finck     {
1870c2c66affSColin Finck         strcatW(wszQuotedCmd, L" ");
1871c2c66affSColin Finck         strcatW(wszQuotedCmd, wszParameters);
1872c2c66affSColin Finck     }
1873c2c66affSColin Finck 
1874c2c66affSColin Finck     TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(wszKeyname));
1875c2c66affSColin Finck 
1876c2c66affSColin Finck     if (*wszKeyname)
1877c2c66affSColin Finck         retval = execute_from_key(wszKeyname, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
1878c2c66affSColin Finck     else
1879c2c66affSColin Finck         retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out);
188006b6833cSKatayama Hirofumi MZ 
1881c2c66affSColin Finck     return retval;
1882c2c66affSColin Finck }
1883c2c66affSColin Finck 
SHELL_execute_url(LPCWSTR lpFile,LPCWSTR wcmd,LPSHELLEXECUTEINFOW psei,LPSHELLEXECUTEINFOW psei_out,SHELL_ExecuteW32 execfunc)1884c2c66affSColin Finck static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
1885c2c66affSColin Finck {
1886c2c66affSColin Finck     UINT_PTR retval;
188706b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> lpstrProtocol;
1888c2c66affSColin Finck     LPCWSTR lpstrRes;
1889c2c66affSColin Finck     INT iSize;
1890c2c66affSColin Finck     DWORD len;
1891c2c66affSColin Finck 
1892c2c66affSColin Finck     lpstrRes = strchrW(lpFile, ':');
1893c2c66affSColin Finck     if (lpstrRes)
1894c2c66affSColin Finck         iSize = lpstrRes - lpFile;
1895c2c66affSColin Finck     else
1896c2c66affSColin Finck         iSize = strlenW(lpFile);
1897c2c66affSColin Finck 
1898c2c66affSColin Finck     TRACE("Got URL: %s\n", debugstr_w(lpFile));
1899c2c66affSColin Finck     /* Looking for ...<protocol>\shell\<lpVerb>\command */
190083be315aSHermès Bélusca-Maïto     len = iSize + lstrlenW(L"\\shell\\") + lstrlenW(L"\\command") + 1;
1901c2c66affSColin Finck     if (psei->lpVerb && *psei->lpVerb)
1902c2c66affSColin Finck         len += lstrlenW(psei->lpVerb);
1903c2c66affSColin Finck     else
190483be315aSHermès Bélusca-Maïto         len += lstrlenW(L"open");
190506b6833cSKatayama Hirofumi MZ     lpstrProtocol.Allocate(len);
1906c2c66affSColin Finck     memcpy(lpstrProtocol, lpFile, iSize * sizeof(WCHAR));
1907c2c66affSColin Finck     lpstrProtocol[iSize] = '\0';
190883be315aSHermès Bélusca-Maïto     strcatW(lpstrProtocol, L"\\shell\\");
190983be315aSHermès Bélusca-Maïto     strcatW(lpstrProtocol, psei->lpVerb && *psei->lpVerb ? psei->lpVerb : L"open");
191083be315aSHermès Bélusca-Maïto     strcatW(lpstrProtocol, L"\\command");
1911c2c66affSColin Finck 
1912c2c66affSColin Finck     retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters,
1913c2c66affSColin Finck                               wcmd, execfunc, psei, psei_out);
191406b6833cSKatayama Hirofumi MZ 
1915c2c66affSColin Finck     return retval;
1916c2c66affSColin Finck }
1917c2c66affSColin Finck 
do_error_dialog(UINT_PTR retval,HWND hwnd,WCHAR * filename)1918c2c66affSColin Finck static void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename)
1919c2c66affSColin Finck {
1920c2c66affSColin Finck     WCHAR msg[2048];
1921c2c66affSColin Finck     DWORD_PTR msgArguments[3]  = { (DWORD_PTR)filename, 0, 0 };
1922c2c66affSColin Finck     DWORD error_code;
1923c2c66affSColin Finck 
1924c2c66affSColin Finck     error_code = GetLastError();
1925c2c66affSColin Finck     if (retval == SE_ERR_NOASSOC)
192683be315aSHermès Bélusca-Maïto         LoadStringW(shell32_hInstance, IDS_SHLEXEC_NOASSOC, msg, ARRAY_SIZE(msg));
1927c2c66affSColin Finck     else
1928c2c66affSColin Finck         FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
1929c2c66affSColin Finck                        NULL,
1930c2c66affSColin Finck                        error_code,
1931c2c66affSColin Finck                        LANG_USER_DEFAULT,
1932c2c66affSColin Finck                        msg,
193383be315aSHermès Bélusca-Maïto                        ARRAY_SIZE(msg),
1934c2c66affSColin Finck                        (va_list*)msgArguments);
1935c2c66affSColin Finck 
1936c2c66affSColin Finck     MessageBoxW(hwnd, msg, NULL, MB_ICONERROR);
1937c2c66affSColin Finck }
1938c2c66affSColin Finck 
expand_environment(const WCHAR * str)1939c2c66affSColin Finck static WCHAR *expand_environment( const WCHAR *str )
1940c2c66affSColin Finck {
194106b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> buf;
1942c2c66affSColin Finck     DWORD len;
1943c2c66affSColin Finck 
1944c2c66affSColin Finck     len = ExpandEnvironmentStringsW(str, NULL, 0);
1945c2c66affSColin Finck     if (!len) return NULL;
1946c2c66affSColin Finck 
194706b6833cSKatayama Hirofumi MZ     if (!buf.Allocate(len))
194806b6833cSKatayama Hirofumi MZ         return NULL;
1949c2c66affSColin Finck 
1950c2c66affSColin Finck     len = ExpandEnvironmentStringsW(str, buf, len);
1951c2c66affSColin Finck     if (!len)
1952c2c66affSColin Finck         return NULL;
195306b6833cSKatayama Hirofumi MZ 
195406b6833cSKatayama Hirofumi MZ     return buf.Detach();
1955c2c66affSColin Finck }
1956c2c66affSColin Finck 
1957c2c66affSColin Finck /*************************************************************************
1958c2c66affSColin Finck  *    SHELL_execute [Internal]
1959c2c66affSColin Finck  */
SHELL_execute(LPSHELLEXECUTEINFOW sei,SHELL_ExecuteW32 execfunc)1960c2c66affSColin Finck static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
1961c2c66affSColin Finck {
1962c2c66affSColin Finck     static const DWORD unsupportedFlags =
1963f6f5490aSMark Jansen         SEE_MASK_ICON         | SEE_MASK_HOTKEY |
1964c2c66affSColin Finck         SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT |
19655c22ce37SRatin Gao         SEE_MASK_ASYNCOK      | SEE_MASK_HMONITOR;
1966c2c66affSColin Finck 
1967c2c66affSColin Finck     DWORD len;
1968c2c66affSColin Finck     UINT_PTR retval = SE_ERR_NOASSOC;
1969c2c66affSColin Finck     BOOL appKnownSingular = FALSE;
1970c2c66affSColin Finck 
1971c2c66affSColin Finck     /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */
197206b6833cSKatayama Hirofumi MZ     SHELLEXECUTEINFOW sei_tmp = *sei;
1973c2c66affSColin Finck 
1974c2c66affSColin Finck     TRACE("mask=0x%08x hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n",
1975c2c66affSColin Finck           sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb),
1976c2c66affSColin Finck           debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters),
1977c2c66affSColin Finck           debugstr_w(sei_tmp.lpDirectory), sei_tmp.nShow,
1978c2c66affSColin Finck           ((sei_tmp.fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME) ?
1979c2c66affSColin Finck           debugstr_w(sei_tmp.lpClass) : "not used");
1980c2c66affSColin Finck 
1981c2c66affSColin Finck     sei->hProcess = NULL;
1982c2c66affSColin Finck 
1983c2c66affSColin Finck     /* make copies of all path/command strings */
198406b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> wszApplicationName;
198506b6833cSKatayama Hirofumi MZ     DWORD dwApplicationNameLen = MAX_PATH + 2;
1986c2c66affSColin Finck     if (!sei_tmp.lpFile)
1987c2c66affSColin Finck     {
198806b6833cSKatayama Hirofumi MZ         wszApplicationName.Allocate(dwApplicationNameLen);
1989c2c66affSColin Finck         *wszApplicationName = '\0';
1990c2c66affSColin Finck     }
1991c2c66affSColin Finck     else if (*sei_tmp.lpFile == '\"' && sei_tmp.lpFile[(len = strlenW(sei_tmp.lpFile))-1] == '\"')
1992c2c66affSColin Finck     {
1993c2c66affSColin Finck         if(len-1 >= dwApplicationNameLen)
1994c2c66affSColin Finck             dwApplicationNameLen = len;
1995c2c66affSColin Finck 
199606b6833cSKatayama Hirofumi MZ         wszApplicationName.Allocate(dwApplicationNameLen);
1997c2c66affSColin Finck         memcpy(wszApplicationName, sei_tmp.lpFile + 1, len * sizeof(WCHAR));
1998c2c66affSColin Finck 
1999c2c66affSColin Finck         if(len > 2)
2000c2c66affSColin Finck             wszApplicationName[len-2] = '\0';
2001c2c66affSColin Finck         appKnownSingular = TRUE;
2002c2c66affSColin Finck 
2003c2c66affSColin Finck         TRACE("wszApplicationName=%s\n", debugstr_w(wszApplicationName));
2004c2c66affSColin Finck     }
2005c2c66affSColin Finck     else
2006c2c66affSColin Finck     {
2007c2c66affSColin Finck         DWORD l = strlenW(sei_tmp.lpFile) + 1;
2008c2c66affSColin Finck         if(l > dwApplicationNameLen) dwApplicationNameLen = l + 1;
200906b6833cSKatayama Hirofumi MZ         wszApplicationName.Allocate(dwApplicationNameLen);
2010c2c66affSColin Finck         memcpy(wszApplicationName, sei_tmp.lpFile, l * sizeof(WCHAR));
2011d3285841SKatayama Hirofumi MZ 
2012d3285841SKatayama Hirofumi MZ         if (wszApplicationName[2] == 0 && wszApplicationName[1] == L':' &&
2013d3285841SKatayama Hirofumi MZ             ((L'A' <= wszApplicationName[0] && wszApplicationName[0] <= L'Z') ||
2014d3285841SKatayama Hirofumi MZ              (L'a' <= wszApplicationName[0] && wszApplicationName[0] <= L'z')))
2015d3285841SKatayama Hirofumi MZ         {
2016d3285841SKatayama Hirofumi MZ             // 'C:' --> 'C:\'
2017d3285841SKatayama Hirofumi MZ             PathAddBackslashW(wszApplicationName);
2018d3285841SKatayama Hirofumi MZ         }
2019c2c66affSColin Finck     }
2020c2c66affSColin Finck 
202106b6833cSKatayama Hirofumi MZ     WCHAR parametersBuffer[1024];
202206b6833cSKatayama Hirofumi MZ     LPWSTR wszParameters = parametersBuffer;
202306b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> wszParamAlloc;
202406b6833cSKatayama Hirofumi MZ     DWORD parametersLen = _countof(parametersBuffer);
202506b6833cSKatayama Hirofumi MZ 
2026c2c66affSColin Finck     if (sei_tmp.lpParameters)
2027c2c66affSColin Finck     {
2028c2c66affSColin Finck         len = lstrlenW(sei_tmp.lpParameters) + 1;
2029c2c66affSColin Finck         if (len > parametersLen)
2030c2c66affSColin Finck         {
203106b6833cSKatayama Hirofumi MZ             wszParamAlloc.Allocate(len);
203206b6833cSKatayama Hirofumi MZ             wszParameters = wszParamAlloc;
2033c2c66affSColin Finck             parametersLen = len;
2034c2c66affSColin Finck         }
2035c2c66affSColin Finck         strcpyW(wszParameters, sei_tmp.lpParameters);
2036c2c66affSColin Finck     }
2037c2c66affSColin Finck     else
2038c2c66affSColin Finck         *wszParameters = L'\0';
2039c2c66affSColin Finck 
2040089788a5SKatayama Hirofumi MZ     // Get the working directory
204106b6833cSKatayama Hirofumi MZ     WCHAR dirBuffer[MAX_PATH];
204206b6833cSKatayama Hirofumi MZ     LPWSTR wszDir = dirBuffer;
2043089788a5SKatayama Hirofumi MZ     wszDir[0] = UNICODE_NULL;
204406b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> wszDirAlloc;
2045089788a5SKatayama Hirofumi MZ     if (sei_tmp.lpDirectory && *sei_tmp.lpDirectory)
2046c2c66affSColin Finck     {
2047089788a5SKatayama Hirofumi MZ         if (sei_tmp.fMask & SEE_MASK_DOENVSUBST)
2048c2c66affSColin Finck         {
2049089788a5SKatayama Hirofumi MZ             LPWSTR tmp = expand_environment(sei_tmp.lpDirectory);
2050089788a5SKatayama Hirofumi MZ             if (tmp)
2051089788a5SKatayama Hirofumi MZ             {
2052089788a5SKatayama Hirofumi MZ                 wszDirAlloc.Attach(tmp);
205306b6833cSKatayama Hirofumi MZ                 wszDir = wszDirAlloc;
2054c2c66affSColin Finck             }
2055c2c66affSColin Finck         }
2056c2c66affSColin Finck         else
2057089788a5SKatayama Hirofumi MZ         {
2058089788a5SKatayama Hirofumi MZ             __SHCloneStrW(&wszDirAlloc, sei_tmp.lpDirectory);
2059089788a5SKatayama Hirofumi MZ             if (wszDirAlloc)
2060089788a5SKatayama Hirofumi MZ                 wszDir = wszDirAlloc;
2061089788a5SKatayama Hirofumi MZ         }
2062089788a5SKatayama Hirofumi MZ     }
2063089788a5SKatayama Hirofumi MZ     if (!wszDir[0])
2064089788a5SKatayama Hirofumi MZ     {
2065089788a5SKatayama Hirofumi MZ         ::GetCurrentDirectoryW(_countof(dirBuffer), dirBuffer);
2066089788a5SKatayama Hirofumi MZ         wszDir = dirBuffer;
2067089788a5SKatayama Hirofumi MZ     }
2068089788a5SKatayama Hirofumi MZ     // NOTE: ShellExecute should accept the invalid working directory for historical reason.
2069089788a5SKatayama Hirofumi MZ     if (!PathIsDirectoryW(wszDir))
2070089788a5SKatayama Hirofumi MZ     {
2071089788a5SKatayama Hirofumi MZ         INT iDrive = PathGetDriveNumberW(wszDir);
2072089788a5SKatayama Hirofumi MZ         if (iDrive >= 0)
2073089788a5SKatayama Hirofumi MZ         {
2074089788a5SKatayama Hirofumi MZ             PathStripToRootW(wszDir);
2075089788a5SKatayama Hirofumi MZ             if (!PathIsDirectoryW(wszDir))
2076089788a5SKatayama Hirofumi MZ             {
2077089788a5SKatayama Hirofumi MZ                 ::GetWindowsDirectoryW(dirBuffer, _countof(dirBuffer));
2078089788a5SKatayama Hirofumi MZ                 wszDir = dirBuffer;
2079089788a5SKatayama Hirofumi MZ             }
2080089788a5SKatayama Hirofumi MZ         }
2081089788a5SKatayama Hirofumi MZ     }
2082c2c66affSColin Finck 
2083c2c66affSColin Finck     /* adjust string pointers to point to the new buffers */
2084c2c66affSColin Finck     sei_tmp.lpFile = wszApplicationName;
2085c2c66affSColin Finck     sei_tmp.lpParameters = wszParameters;
2086c2c66affSColin Finck     sei_tmp.lpDirectory = wszDir;
2087c2c66affSColin Finck 
2088c2c66affSColin Finck     if (sei_tmp.fMask & unsupportedFlags)
2089c2c66affSColin Finck     {
2090c2c66affSColin Finck         FIXME("flags ignored: 0x%08x\n", sei_tmp.fMask & unsupportedFlags);
2091c2c66affSColin Finck     }
2092c2c66affSColin Finck 
2093c2c66affSColin Finck     /* process the IDList */
2094f6f5490aSMark Jansen     if (sei_tmp.fMask & SEE_MASK_IDLIST &&
2095f6f5490aSMark Jansen         (sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) != SEE_MASK_INVOKEIDLIST)
2096c2c66affSColin Finck     {
2097c2c66affSColin Finck         CComPtr<IShellExecuteHookW> pSEH;
2098c2c66affSColin Finck 
2099c2c66affSColin Finck         HRESULT hr = SHBindToParent((LPCITEMIDLIST)sei_tmp.lpIDList, IID_PPV_ARG(IShellExecuteHookW, &pSEH), NULL);
2100c2c66affSColin Finck 
2101c2c66affSColin Finck         if (SUCCEEDED(hr))
2102c2c66affSColin Finck         {
2103c2c66affSColin Finck             hr = pSEH->Execute(&sei_tmp);
2104c2c66affSColin Finck             if (hr == S_OK)
2105c2c66affSColin Finck                 return TRUE;
2106c2c66affSColin Finck         }
2107c2c66affSColin Finck 
2108c2c66affSColin Finck         SHGetPathFromIDListW((LPCITEMIDLIST)sei_tmp.lpIDList, wszApplicationName);
2109c2c66affSColin Finck         appKnownSingular = TRUE;
2110c2c66affSColin Finck         TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName));
2111c2c66affSColin Finck     }
2112c2c66affSColin Finck 
2113766d04d9SKatayama Hirofumi MZ     if ((sei_tmp.fMask & SEE_MASK_DOENVSUBST) && !StrIsNullOrEmpty(sei_tmp.lpFile))
2114c2c66affSColin Finck     {
211506b6833cSKatayama Hirofumi MZ         WCHAR *tmp = expand_environment(sei_tmp.lpFile);
211606b6833cSKatayama Hirofumi MZ         if (tmp)
2117c2c66affSColin Finck         {
211806b6833cSKatayama Hirofumi MZ             wszApplicationName.Attach(tmp);
211906b6833cSKatayama Hirofumi MZ             sei_tmp.lpFile = wszApplicationName;
2120c2c66affSColin Finck         }
2121c2c66affSColin Finck     }
2122c2c66affSColin Finck 
2123f6f5490aSMark Jansen     if ((sei_tmp.fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_INVOKEIDLIST)
2124f6f5490aSMark Jansen     {
2125ce306b83SMark Jansen         HRESULT hr = ShellExecute_ContextMenuVerb(&sei_tmp);
2126f6f5490aSMark Jansen         if (SUCCEEDED(hr))
2127f6f5490aSMark Jansen         {
2128f6f5490aSMark Jansen             sei->hInstApp = (HINSTANCE)42;
2129f6f5490aSMark Jansen             return TRUE;
2130f6f5490aSMark Jansen         }
2131f6f5490aSMark Jansen     }
2132f6f5490aSMark Jansen 
2133ce306b83SMark Jansen     if (ERROR_SUCCESS == ShellExecute_FromContextMenuHandlers(&sei_tmp))
2134c2c66affSColin Finck     {
2135c2c66affSColin Finck         sei->hInstApp = (HINSTANCE) 33;
2136c2c66affSColin Finck         return TRUE;
2137c2c66affSColin Finck     }
2138c2c66affSColin Finck 
2139c2c66affSColin Finck     if (sei_tmp.fMask & SEE_MASK_CLASSALL)
2140c2c66affSColin Finck     {
2141c2c66affSColin Finck         retval = SHELL_execute_class(wszApplicationName, &sei_tmp, sei, execfunc);
2142c2c66affSColin Finck         if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
2143c2c66affSColin Finck         {
2144c2c66affSColin Finck             OPENASINFO Info;
2145c2c66affSColin Finck 
2146c2c66affSColin Finck             //FIXME
2147c2c66affSColin Finck             // need full path
2148c2c66affSColin Finck 
2149c2c66affSColin Finck             Info.pcszFile = wszApplicationName;
2150c2c66affSColin Finck             Info.pcszClass = NULL;
2151c2c66affSColin Finck             Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
2152c2c66affSColin Finck 
2153c2c66affSColin Finck             //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
2154c2c66affSColin Finck             DBG_UNREFERENCED_LOCAL_VARIABLE(Info);
2155c2c66affSColin Finck             do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
2156c2c66affSColin Finck         }
2157c2c66affSColin Finck         return retval > 32;
2158c2c66affSColin Finck     }
2159c2c66affSColin Finck 
21606f277e97SKatayama Hirofumi MZ     if (!(sei_tmp.fMask & SEE_MASK_IDLIST) && // Not an ID List
21616f277e97SKatayama Hirofumi MZ         (StrCmpNIW(sei_tmp.lpFile, L"shell:", 6) == 0 ||
21626f277e97SKatayama Hirofumi MZ          StrCmpNW(sei_tmp.lpFile, L"::{", 3) == 0))
21636f277e97SKatayama Hirofumi MZ     {
21646f277e97SKatayama Hirofumi MZ         CComHeapPtr<ITEMIDLIST> pidlParsed;
21656f277e97SKatayama Hirofumi MZ         HRESULT hr = SHParseDisplayName(sei_tmp.lpFile, NULL, &pidlParsed, 0, NULL);
21666f277e97SKatayama Hirofumi MZ         if (SUCCEEDED(hr) && SHELL_InvokePidl(&sei_tmp, pidlParsed))
21676f277e97SKatayama Hirofumi MZ         {
21686f277e97SKatayama Hirofumi MZ             sei_tmp.hInstApp = (HINSTANCE)UlongToHandle(42);
21696f277e97SKatayama Hirofumi MZ             return TRUE;
21706f277e97SKatayama Hirofumi MZ         }
21716f277e97SKatayama Hirofumi MZ     }
21726f277e97SKatayama Hirofumi MZ 
2173c2c66affSColin Finck     /* Has the IDList not yet been translated? */
2174c2c66affSColin Finck     if (sei_tmp.fMask & SEE_MASK_IDLIST)
2175c2c66affSColin Finck     {
2176c2c66affSColin Finck         appKnownSingular = SHELL_translate_idlist( &sei_tmp, wszParameters,
2177c2c66affSColin Finck                            parametersLen,
2178c2c66affSColin Finck                            wszApplicationName,
2179c2c66affSColin Finck                            dwApplicationNameLen );
2180c2c66affSColin Finck     }
2181c2c66affSColin Finck 
2182c2c66affSColin Finck     /* convert file URLs */
2183c2c66affSColin Finck     if (UrlIsFileUrlW(sei_tmp.lpFile))
2184c2c66affSColin Finck     {
218506b6833cSKatayama Hirofumi MZ         CHeapPtr<WCHAR, CLocalAllocator> buf;
218606b6833cSKatayama Hirofumi MZ         DWORD size = MAX_PATH;
218706b6833cSKatayama Hirofumi MZ         if (!buf.Allocate(size) || FAILED(PathCreateFromUrlW(sei_tmp.lpFile, buf, &size, 0)))
2188c2c66affSColin Finck             return SE_ERR_OOM;
2189c2c66affSColin Finck 
219006b6833cSKatayama Hirofumi MZ         wszApplicationName.Attach(buf.Detach());
2191c2c66affSColin Finck         sei_tmp.lpFile = wszApplicationName;
2192c2c66affSColin Finck     }
2193c2c66affSColin Finck 
2194c2c66affSColin Finck     /* Else, try to execute the filename */
2195c2c66affSColin Finck     TRACE("execute: %s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir));
2196c2c66affSColin Finck 
2197c2c66affSColin Finck     /* separate out command line arguments from executable file name */
2198266e2e50SKatayama Hirofumi MZ     LPCWSTR lpFile = sei_tmp.lpFile;
2199c2c66affSColin Finck     if (!*sei_tmp.lpParameters && !appKnownSingular)
2200c2c66affSColin Finck     {
2201c2c66affSColin Finck         /* If the executable path is quoted, handle the rest of the command line as parameters. */
2202c2c66affSColin Finck         if (sei_tmp.lpFile[0] == L'"')
2203c2c66affSColin Finck         {
2204266e2e50SKatayama Hirofumi MZ             LPWSTR pszArgs = PathGetArgsW(wszApplicationName);
2205266e2e50SKatayama Hirofumi MZ             PathRemoveArgsW(wszApplicationName);
2206266e2e50SKatayama Hirofumi MZ             PathUnquoteSpacesW(wszApplicationName);
2207266e2e50SKatayama Hirofumi MZ             parametersLen = lstrlenW(pszArgs);
2208266e2e50SKatayama Hirofumi MZ             if (parametersLen < _countof(parametersBuffer))
2209c2c66affSColin Finck             {
2210266e2e50SKatayama Hirofumi MZ                 StringCchCopyW(parametersBuffer, _countof(parametersBuffer), pszArgs);
2211266e2e50SKatayama Hirofumi MZ                 wszParameters = parametersBuffer;
2212c2c66affSColin Finck             }
2213c2c66affSColin Finck             else
2214266e2e50SKatayama Hirofumi MZ             {
2215266e2e50SKatayama Hirofumi MZ                 wszParamAlloc.Attach(StrDupW(pszArgs));
2216266e2e50SKatayama Hirofumi MZ                 wszParameters = wszParamAlloc;
2217266e2e50SKatayama Hirofumi MZ             }
2218c2c66affSColin Finck         }
22191b3eed58SDoug Lyons         /* We have to test sei instead of sei_tmp because sei_tmp had its
22201b3eed58SDoug Lyons          * input fMask modified above in SHELL_translate_idlist.
22211b3eed58SDoug Lyons          * This code is needed to handle the case where we only have an
22221b3eed58SDoug Lyons          * lpIDList with multiple CLSID/PIDL's (not 'My Computer' only) */
22231b3eed58SDoug Lyons         else if ((sei->fMask & SEE_MASK_IDLIST) == SEE_MASK_IDLIST)
22241b3eed58SDoug Lyons         {
22251b3eed58SDoug Lyons             WCHAR buffer[MAX_PATH], xlpFile[MAX_PATH];
22261b3eed58SDoug Lyons             LPWSTR space, s;
22271b3eed58SDoug Lyons 
22281b3eed58SDoug Lyons             LPWSTR beg = wszApplicationName;
22291b3eed58SDoug Lyons             for(s = beg; (space = const_cast<LPWSTR>(strchrW(s, L' '))); s = space + 1)
22301b3eed58SDoug Lyons             {
22311b3eed58SDoug Lyons                 int idx = space - sei_tmp.lpFile;
22321b3eed58SDoug Lyons                 memcpy(buffer, sei_tmp.lpFile, idx * sizeof(WCHAR));
22331b3eed58SDoug Lyons                 buffer[idx] = '\0';
22341b3eed58SDoug Lyons 
22351b3eed58SDoug Lyons                 if (SearchPathW(*sei_tmp.lpDirectory ? sei_tmp.lpDirectory : NULL,
22361b3eed58SDoug Lyons                     buffer, L".exe", _countof(xlpFile), xlpFile, NULL))
22371b3eed58SDoug Lyons                 {
22381b3eed58SDoug Lyons                     /* separate out command from parameter string */
22391b3eed58SDoug Lyons                     LPCWSTR p = space + 1;
22401b3eed58SDoug Lyons 
22411b3eed58SDoug Lyons                     while(isspaceW(*p))
22421b3eed58SDoug Lyons                         ++p;
22431b3eed58SDoug Lyons 
22441b3eed58SDoug Lyons                     strcpyW(wszParameters, p);
22451b3eed58SDoug Lyons                     *space = L'\0';
22461b3eed58SDoug Lyons 
22471b3eed58SDoug Lyons                     break;
22481b3eed58SDoug Lyons                 }
22491b3eed58SDoug Lyons             }
2250c2c66affSColin Finck         }
2251c2c66affSColin Finck     }
2252c2c66affSColin Finck 
225306b6833cSKatayama Hirofumi MZ     WCHAR wcmdBuffer[1024];
225406b6833cSKatayama Hirofumi MZ     LPWSTR wcmd = wcmdBuffer;
225506b6833cSKatayama Hirofumi MZ     DWORD wcmdLen = _countof(wcmdBuffer);
225606b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> wcmdAlloc;
22579b716539SAlex Miccolis 
22589b716539SAlex Miccolis     /* Only execute if it has an executable extension */
22599b716539SAlex Miccolis     if (PathIsExeW(lpFile))
22609b716539SAlex Miccolis     {
2261c2c66affSColin Finck         len = lstrlenW(wszApplicationName) + 3;
2262c2c66affSColin Finck         if (sei_tmp.lpParameters[0])
2263c2c66affSColin Finck             len += 1 + lstrlenW(wszParameters);
2264c2c66affSColin Finck         if (len > wcmdLen)
2265c2c66affSColin Finck         {
226606b6833cSKatayama Hirofumi MZ             wcmdAlloc.Allocate(len);
226706b6833cSKatayama Hirofumi MZ             wcmd = wcmdAlloc;
2268c2c66affSColin Finck             wcmdLen = len;
2269c2c66affSColin Finck         }
227006b6833cSKatayama Hirofumi MZ         swprintf(wcmd, L"\"%s\"", (LPWSTR)wszApplicationName);
2271c2c66affSColin Finck         if (sei_tmp.lpParameters[0])
2272c2c66affSColin Finck         {
2273c2c66affSColin Finck             strcatW(wcmd, L" ");
2274c2c66affSColin Finck             strcatW(wcmd, wszParameters);
2275c2c66affSColin Finck         }
2276c2c66affSColin Finck 
2277c2c66affSColin Finck         retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei);
2278c2c66affSColin Finck         if (retval > 32)
2279c2c66affSColin Finck             return TRUE;
2280c2c66affSColin Finck     }
2281c2c66affSColin Finck 
2282c2c66affSColin Finck     /* Else, try to find the executable */
228306b6833cSKatayama Hirofumi MZ     WCHAR wszKeyname[256];
228406b6833cSKatayama Hirofumi MZ     CHeapPtr<WCHAR, CLocalAllocator> env;
228506b6833cSKatayama Hirofumi MZ     wcmd[0] = UNICODE_NULL;
2286c2c66affSColin Finck     retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, wszKeyname, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
2287c2c66affSColin Finck     if (retval > 32)  /* Found */
2288c2c66affSColin Finck     {
2289c2c66affSColin Finck         retval = SHELL_quote_and_execute(wcmd, wszParameters, wszKeyname,
2290c2c66affSColin Finck                                          wszApplicationName, env, &sei_tmp,
2291c2c66affSColin Finck                                          sei, execfunc);
2292c2c66affSColin Finck     }
2293c2c66affSColin Finck     else if (PathIsDirectoryW(lpFile))
2294c2c66affSColin Finck     {
2295c2c66affSColin Finck         WCHAR wExec[MAX_PATH];
229606b6833cSKatayama Hirofumi MZ         CHeapPtr<WCHAR, CLocalAllocator> lpQuotedFile;
229706b6833cSKatayama Hirofumi MZ         if (lpQuotedFile.Allocate(strlenW(lpFile) + 3))
2298c2c66affSColin Finck         {
2299c2c66affSColin Finck             retval = SHELL_FindExecutable(sei_tmp.lpDirectory, L"explorer",
230083be315aSHermès Bélusca-Maïto                                           L"open", wExec, MAX_PATH,
2301c2c66affSColin Finck                                           NULL, &env, NULL, NULL);
2302c2c66affSColin Finck             if (retval > 32)
2303c2c66affSColin Finck             {
2304c2c66affSColin Finck                 swprintf(lpQuotedFile, L"\"%s\"", lpFile);
2305c2c66affSColin Finck                 retval = SHELL_quote_and_execute(wExec, lpQuotedFile,
2306c2c66affSColin Finck                                                  wszKeyname,
2307c2c66affSColin Finck                                                  wszApplicationName, env,
2308c2c66affSColin Finck                                                  &sei_tmp, sei, execfunc);
2309c2c66affSColin Finck             }
2310c2c66affSColin Finck         }
2311c2c66affSColin Finck         else
2312c2c66affSColin Finck             retval = 0; /* Out of memory */
2313c2c66affSColin Finck     }
2314c2c66affSColin Finck     else if (PathIsURLW(lpFile))    /* File not found, check for URL */
2315c2c66affSColin Finck     {
2316c2c66affSColin Finck         retval = SHELL_execute_url(lpFile, wcmd, &sei_tmp, sei, execfunc );
2317c2c66affSColin Finck     }
2318c2c66affSColin Finck     /* Check if file specified is in the form www.??????.*** */
2319c2c66affSColin Finck     else if (!strncmpiW(lpFile, L"www", 3))
2320c2c66affSColin Finck     {
2321c2c66affSColin Finck         /* if so, prefix lpFile with http:// and call ShellExecute */
2322c2c66affSColin Finck         WCHAR lpstrTmpFile[256];
2323c2c66affSColin Finck         strcpyW(lpstrTmpFile, L"http://");
2324c2c66affSColin Finck         strcatW(lpstrTmpFile, lpFile);
2325c2c66affSColin Finck         retval = (UINT_PTR)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0);
2326c2c66affSColin Finck     }
2327c2c66affSColin Finck 
2328c2c66affSColin Finck     TRACE("retval %lu\n", retval);
2329c2c66affSColin Finck 
2330c2c66affSColin Finck     if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
2331c2c66affSColin Finck     {
2332c2c66affSColin Finck         OPENASINFO Info;
2333c2c66affSColin Finck 
2334c2c66affSColin Finck         //FIXME
2335c2c66affSColin Finck         // need full path
2336c2c66affSColin Finck 
2337c2c66affSColin Finck         Info.pcszFile = wszApplicationName;
2338c2c66affSColin Finck         Info.pcszClass = NULL;
2339c2c66affSColin Finck         Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
2340c2c66affSColin Finck 
2341c2c66affSColin Finck         //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
2342c2c66affSColin Finck         DBG_UNREFERENCED_LOCAL_VARIABLE(Info);
2343c2c66affSColin Finck         do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
2344c2c66affSColin Finck     }
2345c2c66affSColin Finck 
2346c2c66affSColin Finck     sei->hInstApp = (HINSTANCE)(retval > 32 ? 33 : retval);
2347c2c66affSColin Finck 
2348c2c66affSColin Finck     return retval > 32;
2349c2c66affSColin Finck }
2350c2c66affSColin Finck 
2351c2c66affSColin Finck /*************************************************************************
2352c2c66affSColin Finck  * ShellExecuteA            [SHELL32.290]
2353c2c66affSColin Finck  */
ShellExecuteA(HWND hWnd,LPCSTR lpVerb,LPCSTR lpFile,LPCSTR lpParameters,LPCSTR lpDirectory,INT iShowCmd)2354c2c66affSColin Finck HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile,
2355c2c66affSColin Finck                                LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
2356c2c66affSColin Finck {
2357c2c66affSColin Finck     SHELLEXECUTEINFOA sei;
2358c2c66affSColin Finck 
2359c2c66affSColin Finck     TRACE("%p,%s,%s,%s,%s,%d\n",
2360c2c66affSColin Finck           hWnd, debugstr_a(lpVerb), debugstr_a(lpFile),
2361c2c66affSColin Finck           debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd);
2362c2c66affSColin Finck 
2363c2c66affSColin Finck     sei.cbSize = sizeof(sei);
2364c2c66affSColin Finck     sei.fMask = SEE_MASK_FLAG_NO_UI;
2365c2c66affSColin Finck     sei.hwnd = hWnd;
2366c2c66affSColin Finck     sei.lpVerb = lpVerb;
2367c2c66affSColin Finck     sei.lpFile = lpFile;
2368c2c66affSColin Finck     sei.lpParameters = lpParameters;
2369c2c66affSColin Finck     sei.lpDirectory = lpDirectory;
2370c2c66affSColin Finck     sei.nShow = iShowCmd;
2371c2c66affSColin Finck     sei.lpIDList = 0;
2372c2c66affSColin Finck     sei.lpClass = 0;
2373c2c66affSColin Finck     sei.hkeyClass = 0;
2374c2c66affSColin Finck     sei.dwHotKey = 0;
2375c2c66affSColin Finck     sei.hProcess = 0;
2376c2c66affSColin Finck 
2377fd41270dSWhindmar Saksit     if (!(SHGetAppCompatFlags(SHACF_WIN95SHLEXEC) & SHACF_WIN95SHLEXEC))
2378fd41270dSWhindmar Saksit         sei.fMask |= SEE_MASK_NOASYNC;
2379c2c66affSColin Finck     ShellExecuteExA(&sei);
2380c2c66affSColin Finck     return sei.hInstApp;
2381c2c66affSColin Finck }
2382c2c66affSColin Finck 
2383044f1819SKatayama Hirofumi MZ static DWORD
ShellExecute_Normal(_Inout_ LPSHELLEXECUTEINFOW sei)2384044f1819SKatayama Hirofumi MZ ShellExecute_Normal(_Inout_ LPSHELLEXECUTEINFOW sei)
2385044f1819SKatayama Hirofumi MZ {
2386044f1819SKatayama Hirofumi MZ     // FIXME
2387044f1819SKatayama Hirofumi MZ     return SHELL_execute(sei, SHELL_ExecuteW) ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND;
2388044f1819SKatayama Hirofumi MZ }
2389044f1819SKatayama Hirofumi MZ 
2390044f1819SKatayama Hirofumi MZ static VOID
ShellExecute_ShowError(_In_ const SHELLEXECUTEINFOW * ExecInfo,_In_opt_ LPCWSTR pszCaption,_In_ DWORD dwError)2391044f1819SKatayama Hirofumi MZ ShellExecute_ShowError(
2392044f1819SKatayama Hirofumi MZ     _In_ const SHELLEXECUTEINFOW *ExecInfo,
2393044f1819SKatayama Hirofumi MZ     _In_opt_ LPCWSTR pszCaption,
2394044f1819SKatayama Hirofumi MZ     _In_ DWORD dwError)
2395044f1819SKatayama Hirofumi MZ {
2396044f1819SKatayama Hirofumi MZ     // FIXME: Show error message
2397044f1819SKatayama Hirofumi MZ }
2398044f1819SKatayama Hirofumi MZ 
2399c2c66affSColin Finck /*************************************************************************
2400c2c66affSColin Finck  * ShellExecuteExA                [SHELL32.292]
2401c2c66affSColin Finck  */
2402c2c66affSColin Finck BOOL
2403c2c66affSColin Finck WINAPI
2404c2c66affSColin Finck DECLSPEC_HOTPATCH
ShellExecuteExA(LPSHELLEXECUTEINFOA sei)2405c2c66affSColin Finck ShellExecuteExA(LPSHELLEXECUTEINFOA sei)
2406c2c66affSColin Finck {
2407c2c66affSColin Finck     SHELLEXECUTEINFOW seiW;
2408c2c66affSColin Finck     BOOL ret;
2409c2c66affSColin Finck     WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL, *wClass = NULL;
2410c2c66affSColin Finck 
2411c2c66affSColin Finck     TRACE("%p\n", sei);
2412c2c66affSColin Finck 
2413044f1819SKatayama Hirofumi MZ     if (sei->cbSize != sizeof(SHELLEXECUTEINFOA))
2414044f1819SKatayama Hirofumi MZ     {
2415044f1819SKatayama Hirofumi MZ         sei->hInstApp = (HINSTANCE)ERROR_ACCESS_DENIED;
2416044f1819SKatayama Hirofumi MZ         SetLastError(ERROR_ACCESS_DENIED);
2417044f1819SKatayama Hirofumi MZ         return FALSE;
2418044f1819SKatayama Hirofumi MZ     }
2419044f1819SKatayama Hirofumi MZ 
2420c2c66affSColin Finck     memcpy(&seiW, sei, sizeof(SHELLEXECUTEINFOW));
2421c2c66affSColin Finck 
2422044f1819SKatayama Hirofumi MZ     seiW.cbSize = sizeof(SHELLEXECUTEINFOW);
2423044f1819SKatayama Hirofumi MZ 
2424c2c66affSColin Finck     if (sei->lpVerb)
2425c2c66affSColin Finck         seiW.lpVerb = __SHCloneStrAtoW(&wVerb, sei->lpVerb);
2426c2c66affSColin Finck 
2427c2c66affSColin Finck     if (sei->lpFile)
2428c2c66affSColin Finck         seiW.lpFile = __SHCloneStrAtoW(&wFile, sei->lpFile);
2429c2c66affSColin Finck 
2430c2c66affSColin Finck     if (sei->lpParameters)
2431c2c66affSColin Finck         seiW.lpParameters = __SHCloneStrAtoW(&wParameters, sei->lpParameters);
2432c2c66affSColin Finck 
2433c2c66affSColin Finck     if (sei->lpDirectory)
2434c2c66affSColin Finck         seiW.lpDirectory = __SHCloneStrAtoW(&wDirectory, sei->lpDirectory);
2435c2c66affSColin Finck 
2436c2c66affSColin Finck     if ((sei->fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME && sei->lpClass)
2437c2c66affSColin Finck         seiW.lpClass = __SHCloneStrAtoW(&wClass, sei->lpClass);
2438c2c66affSColin Finck     else
2439c2c66affSColin Finck         seiW.lpClass = NULL;
2440c2c66affSColin Finck 
2441044f1819SKatayama Hirofumi MZ     ret = ShellExecuteExW(&seiW);
2442c2c66affSColin Finck 
2443c2c66affSColin Finck     sei->hInstApp = seiW.hInstApp;
2444c2c66affSColin Finck 
2445c2c66affSColin Finck     if (sei->fMask & SEE_MASK_NOCLOSEPROCESS)
2446c2c66affSColin Finck         sei->hProcess = seiW.hProcess;
2447c2c66affSColin Finck 
2448c2c66affSColin Finck     SHFree(wVerb);
2449c2c66affSColin Finck     SHFree(wFile);
2450c2c66affSColin Finck     SHFree(wParameters);
2451c2c66affSColin Finck     SHFree(wDirectory);
2452c2c66affSColin Finck     SHFree(wClass);
2453c2c66affSColin Finck 
2454c2c66affSColin Finck     return ret;
2455c2c66affSColin Finck }
2456c2c66affSColin Finck 
2457c2c66affSColin Finck /*************************************************************************
2458c2c66affSColin Finck  * ShellExecuteExW                [SHELL32.293]
2459c2c66affSColin Finck  */
2460c2c66affSColin Finck BOOL
2461c2c66affSColin Finck WINAPI
2462c2c66affSColin Finck DECLSPEC_HOTPATCH
ShellExecuteExW(LPSHELLEXECUTEINFOW sei)2463c2c66affSColin Finck ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
2464c2c66affSColin Finck {
2465044f1819SKatayama Hirofumi MZ     HRESULT hrCoInit;
2466044f1819SKatayama Hirofumi MZ     DWORD dwError;
2467044f1819SKatayama Hirofumi MZ     ULONG fOldMask;
2468044f1819SKatayama Hirofumi MZ 
2469044f1819SKatayama Hirofumi MZ     if (sei->cbSize != sizeof(SHELLEXECUTEINFOW))
2470044f1819SKatayama Hirofumi MZ     {
24713e97f76aSKatayama Hirofumi MZ         sei->hInstApp = (HINSTANCE)UlongToHandle(SE_ERR_ACCESSDENIED);
24723e97f76aSKatayama Hirofumi MZ         SetLastError(ERROR_ACCESS_DENIED);
24733e97f76aSKatayama Hirofumi MZ         return FALSE;
2474044f1819SKatayama Hirofumi MZ     }
24753e97f76aSKatayama Hirofumi MZ 
24763e97f76aSKatayama Hirofumi MZ     hrCoInit = SHCoInitializeAnyApartment();
24773e97f76aSKatayama Hirofumi MZ 
2478044f1819SKatayama Hirofumi MZ     if (SHRegGetBoolUSValueW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
2479044f1819SKatayama Hirofumi MZ                              L"MaximizeApps", FALSE, FALSE))
2480044f1819SKatayama Hirofumi MZ     {
2481044f1819SKatayama Hirofumi MZ         switch (sei->nShow)
2482044f1819SKatayama Hirofumi MZ         {
2483044f1819SKatayama Hirofumi MZ             case SW_SHOW:
2484044f1819SKatayama Hirofumi MZ             case SW_SHOWDEFAULT:
2485044f1819SKatayama Hirofumi MZ             case SW_SHOWNORMAL:
2486044f1819SKatayama Hirofumi MZ             case SW_RESTORE:
2487044f1819SKatayama Hirofumi MZ                 sei->nShow = SW_SHOWMAXIMIZED;
2488044f1819SKatayama Hirofumi MZ                 break;
2489044f1819SKatayama Hirofumi MZ             default:
2490044f1819SKatayama Hirofumi MZ                 break;
2491044f1819SKatayama Hirofumi MZ         }
2492044f1819SKatayama Hirofumi MZ     }
2493044f1819SKatayama Hirofumi MZ 
2494044f1819SKatayama Hirofumi MZ     fOldMask = sei->fMask;
2495044f1819SKatayama Hirofumi MZ 
2496044f1819SKatayama Hirofumi MZ     if (!(fOldMask & SEE_MASK_NOASYNC) && SHELL_InRunDllProcess())
2497044f1819SKatayama Hirofumi MZ         sei->fMask |= SEE_MASK_WAITFORINPUTIDLE | SEE_MASK_NOASYNC;
2498044f1819SKatayama Hirofumi MZ 
2499044f1819SKatayama Hirofumi MZ     dwError = ShellExecute_Normal(sei);
2500044f1819SKatayama Hirofumi MZ 
2501044f1819SKatayama Hirofumi MZ     if (dwError && dwError != ERROR_DLL_NOT_FOUND && dwError != ERROR_CANCELLED)
2502044f1819SKatayama Hirofumi MZ         ShellExecute_ShowError(sei, NULL, dwError);
2503044f1819SKatayama Hirofumi MZ 
2504044f1819SKatayama Hirofumi MZ     sei->fMask = fOldMask;
2505044f1819SKatayama Hirofumi MZ 
2506044f1819SKatayama Hirofumi MZ     if (SUCCEEDED(hrCoInit))
2507044f1819SKatayama Hirofumi MZ         CoUninitialize();
2508044f1819SKatayama Hirofumi MZ 
2509044f1819SKatayama Hirofumi MZ     if (dwError)
2510044f1819SKatayama Hirofumi MZ         SetLastError(dwError);
2511044f1819SKatayama Hirofumi MZ 
2512044f1819SKatayama Hirofumi MZ     return dwError == ERROR_SUCCESS;
2513c2c66affSColin Finck }
2514c2c66affSColin Finck 
2515c2c66affSColin Finck /*************************************************************************
2516c2c66affSColin Finck  * ShellExecuteW            [SHELL32.294]
2517c2c66affSColin Finck  */
ShellExecuteW(HWND hwnd,LPCWSTR lpVerb,LPCWSTR lpFile,LPCWSTR lpParameters,LPCWSTR lpDirectory,INT nShowCmd)2518c2c66affSColin Finck HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile,
2519c2c66affSColin Finck                                LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
2520c2c66affSColin Finck {
2521c2c66affSColin Finck     SHELLEXECUTEINFOW sei;
2522c2c66affSColin Finck 
2523c2c66affSColin Finck     TRACE("\n");
2524c2c66affSColin Finck     sei.cbSize = sizeof(sei);
2525c2c66affSColin Finck     sei.fMask = SEE_MASK_FLAG_NO_UI;
2526c2c66affSColin Finck     sei.hwnd = hwnd;
2527c2c66affSColin Finck     sei.lpVerb = lpVerb;
2528c2c66affSColin Finck     sei.lpFile = lpFile;
2529c2c66affSColin Finck     sei.lpParameters = lpParameters;
2530c2c66affSColin Finck     sei.lpDirectory = lpDirectory;
2531c2c66affSColin Finck     sei.nShow = nShowCmd;
2532c2c66affSColin Finck     sei.lpIDList = 0;
2533c2c66affSColin Finck     sei.lpClass = 0;
2534c2c66affSColin Finck     sei.hkeyClass = 0;
2535c2c66affSColin Finck     sei.dwHotKey = 0;
2536c2c66affSColin Finck     sei.hProcess = 0;
2537c2c66affSColin Finck 
2538fd41270dSWhindmar Saksit     if (!(SHGetAppCompatFlags(SHACF_WIN95SHLEXEC) & SHACF_WIN95SHLEXEC))
2539fd41270dSWhindmar Saksit         sei.fMask |= SEE_MASK_NOASYNC;
2540fd41270dSWhindmar Saksit     ShellExecuteExW(&sei);
2541c2c66affSColin Finck     return sei.hInstApp;
2542c2c66affSColin Finck }
2543c2c66affSColin Finck 
2544c2c66affSColin Finck /*************************************************************************
2545c2c66affSColin Finck  * WOWShellExecute            [SHELL32.@]
2546c2c66affSColin Finck  *
2547c2c66affSColin Finck  * FIXME: the callback function most likely doesn't work the same way on Windows.
2548c2c66affSColin Finck  */
WOWShellExecute(HWND hWnd,LPCSTR lpVerb,LPCSTR lpFile,LPCSTR lpParameters,LPCSTR lpDirectory,INT iShowCmd,void * callback)2549c2c66affSColin Finck EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile,
2550c2c66affSColin Finck         LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback)
2551c2c66affSColin Finck {
2552c2c66affSColin Finck     SHELLEXECUTEINFOW seiW;
2553c2c66affSColin Finck     WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL;
2554c2c66affSColin Finck     HANDLE hProcess = 0;
2555c2c66affSColin Finck 
2556c2c66affSColin Finck     seiW.lpVerb = lpVerb ? __SHCloneStrAtoW(&wVerb, lpVerb) : NULL;
2557c2c66affSColin Finck     seiW.lpFile = lpFile ? __SHCloneStrAtoW(&wFile, lpFile) : NULL;
2558c2c66affSColin Finck     seiW.lpParameters = lpParameters ? __SHCloneStrAtoW(&wParameters, lpParameters) : NULL;
2559c2c66affSColin Finck     seiW.lpDirectory = lpDirectory ? __SHCloneStrAtoW(&wDirectory, lpDirectory) : NULL;
2560c2c66affSColin Finck 
2561c2c66affSColin Finck     seiW.cbSize = sizeof(seiW);
2562c2c66affSColin Finck     seiW.fMask = 0;
2563c2c66affSColin Finck     seiW.hwnd = hWnd;
2564c2c66affSColin Finck     seiW.nShow = iShowCmd;
2565c2c66affSColin Finck     seiW.lpIDList = 0;
2566c2c66affSColin Finck     seiW.lpClass = 0;
2567c2c66affSColin Finck     seiW.hkeyClass = 0;
2568c2c66affSColin Finck     seiW.dwHotKey = 0;
2569c2c66affSColin Finck     seiW.hProcess = hProcess;
2570c2c66affSColin Finck 
2571c2c66affSColin Finck     SHELL_execute(&seiW, (SHELL_ExecuteW32)callback);
2572c2c66affSColin Finck 
2573c2c66affSColin Finck     SHFree(wVerb);
2574c2c66affSColin Finck     SHFree(wFile);
2575c2c66affSColin Finck     SHFree(wParameters);
2576c2c66affSColin Finck     SHFree(wDirectory);
2577c2c66affSColin Finck     return seiW.hInstApp;
2578c2c66affSColin Finck }
2579c2c66affSColin Finck 
2580c2c66affSColin Finck /*************************************************************************
2581cc8b2717SKatayama Hirofumi MZ  * OpenAs_RunDLLW          [SHELL32.@]
2582c2c66affSColin Finck  */
2583cc8b2717SKatayama Hirofumi MZ EXTERN_C void WINAPI
OpenAs_RunDLLW(HWND hwnd,HINSTANCE hinst,LPCWSTR cmdline,int cmdshow)2584cc8b2717SKatayama Hirofumi MZ OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow)
2585c2c66affSColin Finck {
2586cc8b2717SKatayama Hirofumi MZ     OPENASINFO info;
2587cc8b2717SKatayama Hirofumi MZ     TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow);
2588cc8b2717SKatayama Hirofumi MZ 
2589cc8b2717SKatayama Hirofumi MZ     ZeroMemory(&info, sizeof(info));
2590cc8b2717SKatayama Hirofumi MZ     info.pcszFile = cmdline;
2591cc8b2717SKatayama Hirofumi MZ     info.pcszClass = NULL;
2592cc8b2717SKatayama Hirofumi MZ     info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC;
2593cc8b2717SKatayama Hirofumi MZ 
2594cc8b2717SKatayama Hirofumi MZ     SHOpenWithDialog(hwnd, &info);
2595c2c66affSColin Finck }
2596c2c66affSColin Finck 
2597c2c66affSColin Finck /*************************************************************************
2598cc8b2717SKatayama Hirofumi MZ  * OpenAs_RunDLLA          [SHELL32.@]
2599c2c66affSColin Finck  */
2600cc8b2717SKatayama Hirofumi MZ EXTERN_C void WINAPI
OpenAs_RunDLLA(HWND hwnd,HINSTANCE hinst,LPCSTR cmdline,int cmdshow)2601cc8b2717SKatayama Hirofumi MZ OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow)
2602c2c66affSColin Finck {
2603cc8b2717SKatayama Hirofumi MZ     LPWSTR pszCmdLineW = NULL;
2604cc8b2717SKatayama Hirofumi MZ     TRACE("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow);
2605cc8b2717SKatayama Hirofumi MZ 
26063904fd62SMark Jansen     if (cmdline)
2607cc8b2717SKatayama Hirofumi MZ         __SHCloneStrAtoW(&pszCmdLineW, cmdline);
2608cc8b2717SKatayama Hirofumi MZ     OpenAs_RunDLLW(hwnd, hinst, pszCmdLineW, cmdshow);
2609cc8b2717SKatayama Hirofumi MZ     SHFree(pszCmdLineW);
2610c2c66affSColin Finck }
2611bfcbda22SKatayama Hirofumi MZ 
2612bfcbda22SKatayama Hirofumi MZ /*************************************************************************/
2613bfcbda22SKatayama Hirofumi MZ 
2614bfcbda22SKatayama Hirofumi MZ static LPCWSTR
SplitParams(LPCWSTR psz,LPWSTR pszArg0,size_t cchArg0)2615bfcbda22SKatayama Hirofumi MZ SplitParams(LPCWSTR psz, LPWSTR pszArg0, size_t cchArg0)
2616bfcbda22SKatayama Hirofumi MZ {
2617bfcbda22SKatayama Hirofumi MZ     LPCWSTR pch;
2618bfcbda22SKatayama Hirofumi MZ     size_t ich = 0;
2619bfcbda22SKatayama Hirofumi MZ     if (*psz == L'"')
2620bfcbda22SKatayama Hirofumi MZ     {
2621bfcbda22SKatayama Hirofumi MZ         // 1st argument is quoted. the string in quotes is quoted 1st argument.
2622bfcbda22SKatayama Hirofumi MZ         // [pch] --> [pszArg0+ich]
2623bfcbda22SKatayama Hirofumi MZ         for (pch = psz + 1; *pch && ich + 1 < cchArg0; ++ich, ++pch)
2624bfcbda22SKatayama Hirofumi MZ         {
2625bfcbda22SKatayama Hirofumi MZ             if (*pch == L'"' && pch[1] == L'"')
2626bfcbda22SKatayama Hirofumi MZ             {
2627bfcbda22SKatayama Hirofumi MZ                 // doubled double quotations found!
2628bfcbda22SKatayama Hirofumi MZ                 pszArg0[ich] = L'"';
2629bfcbda22SKatayama Hirofumi MZ             }
2630bfcbda22SKatayama Hirofumi MZ             else if (*pch == L'"')
2631bfcbda22SKatayama Hirofumi MZ             {
2632bfcbda22SKatayama Hirofumi MZ                 // single double quotation found!
2633bfcbda22SKatayama Hirofumi MZ                 ++pch;
2634bfcbda22SKatayama Hirofumi MZ                 break;
2635bfcbda22SKatayama Hirofumi MZ             }
2636bfcbda22SKatayama Hirofumi MZ             else
2637bfcbda22SKatayama Hirofumi MZ             {
2638bfcbda22SKatayama Hirofumi MZ                 // otherwise
2639bfcbda22SKatayama Hirofumi MZ                 pszArg0[ich] = *pch;
2640bfcbda22SKatayama Hirofumi MZ             }
2641bfcbda22SKatayama Hirofumi MZ         }
2642bfcbda22SKatayama Hirofumi MZ     }
2643bfcbda22SKatayama Hirofumi MZ     else
2644bfcbda22SKatayama Hirofumi MZ     {
2645bfcbda22SKatayama Hirofumi MZ         // 1st argument is unquoted. non-space sequence is 1st argument.
2646bfcbda22SKatayama Hirofumi MZ         // [pch] --> [pszArg0+ich]
2647bfcbda22SKatayama Hirofumi MZ         for (pch = psz; *pch && !iswspace(*pch) && ich + 1 < cchArg0; ++ich, ++pch)
2648bfcbda22SKatayama Hirofumi MZ         {
2649bfcbda22SKatayama Hirofumi MZ             pszArg0[ich] = *pch;
2650bfcbda22SKatayama Hirofumi MZ         }
2651bfcbda22SKatayama Hirofumi MZ     }
2652bfcbda22SKatayama Hirofumi MZ     pszArg0[ich] = 0;
2653bfcbda22SKatayama Hirofumi MZ 
2654bfcbda22SKatayama Hirofumi MZ     // skip space
2655bfcbda22SKatayama Hirofumi MZ     while (iswspace(*pch))
2656bfcbda22SKatayama Hirofumi MZ         ++pch;
2657bfcbda22SKatayama Hirofumi MZ 
2658bfcbda22SKatayama Hirofumi MZ     return pch;
2659bfcbda22SKatayama Hirofumi MZ }
2660bfcbda22SKatayama Hirofumi MZ 
ShellExecCmdLine(HWND hwnd,LPCWSTR pwszCommand,LPCWSTR pwszStartDir,int nShow,LPVOID pUnused,DWORD dwSeclFlags)2661bfcbda22SKatayama Hirofumi MZ HRESULT WINAPI ShellExecCmdLine(
2662bfcbda22SKatayama Hirofumi MZ     HWND hwnd,
2663bfcbda22SKatayama Hirofumi MZ     LPCWSTR pwszCommand,
2664bfcbda22SKatayama Hirofumi MZ     LPCWSTR pwszStartDir,
2665bfcbda22SKatayama Hirofumi MZ     int nShow,
2666bfcbda22SKatayama Hirofumi MZ     LPVOID pUnused,
2667bfcbda22SKatayama Hirofumi MZ     DWORD dwSeclFlags)
2668bfcbda22SKatayama Hirofumi MZ {
2669bfcbda22SKatayama Hirofumi MZ     SHELLEXECUTEINFOW info;
2670bfcbda22SKatayama Hirofumi MZ     DWORD dwSize, dwError, dwType, dwFlags = SEE_MASK_DOENVSUBST | SEE_MASK_NOASYNC;
2671bfcbda22SKatayama Hirofumi MZ     LPCWSTR pszVerb = NULL;
2672bfcbda22SKatayama Hirofumi MZ     WCHAR szFile[MAX_PATH], szFile2[MAX_PATH];
2673bfcbda22SKatayama Hirofumi MZ     HRESULT hr;
2674bfcbda22SKatayama Hirofumi MZ     LPCWSTR pchParams;
2675bfcbda22SKatayama Hirofumi MZ     LPWSTR lpCommand = NULL;
2676bfcbda22SKatayama Hirofumi MZ 
2677bfcbda22SKatayama Hirofumi MZ     if (pwszCommand == NULL)
2678bfcbda22SKatayama Hirofumi MZ         RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE,
2679bfcbda22SKatayama Hirofumi MZ                        1, (ULONG_PTR*)pwszCommand);
2680bfcbda22SKatayama Hirofumi MZ 
2681bfcbda22SKatayama Hirofumi MZ     __SHCloneStrW(&lpCommand, pwszCommand);
2682bfcbda22SKatayama Hirofumi MZ     StrTrimW(lpCommand, L" \t");
2683bfcbda22SKatayama Hirofumi MZ 
2684bfcbda22SKatayama Hirofumi MZ     if (dwSeclFlags & SECL_NO_UI)
2685bfcbda22SKatayama Hirofumi MZ         dwFlags |= SEE_MASK_FLAG_NO_UI;
2686bfcbda22SKatayama Hirofumi MZ     if (dwSeclFlags & SECL_LOG_USAGE)
2687bfcbda22SKatayama Hirofumi MZ         dwFlags |= SEE_MASK_FLAG_LOG_USAGE;
2688bfcbda22SKatayama Hirofumi MZ     if (dwSeclFlags & SECL_USE_IDLIST)
2689bfcbda22SKatayama Hirofumi MZ         dwFlags |= SEE_MASK_INVOKEIDLIST;
2690bfcbda22SKatayama Hirofumi MZ 
2691bfcbda22SKatayama Hirofumi MZ     if (dwSeclFlags & SECL_RUNAS)
2692bfcbda22SKatayama Hirofumi MZ     {
2693bfcbda22SKatayama Hirofumi MZ         dwSize = 0;
2694f9a55858SKatayama Hirofumi MZ         hr = AssocQueryStringW(ASSOCF_NONE, ASSOCSTR_COMMAND, lpCommand, L"RunAs", NULL, &dwSize);
2695bfcbda22SKatayama Hirofumi MZ         if (SUCCEEDED(hr) && dwSize != 0)
2696bfcbda22SKatayama Hirofumi MZ         {
2697bfcbda22SKatayama Hirofumi MZ             pszVerb = L"runas";
2698bfcbda22SKatayama Hirofumi MZ         }
2699bfcbda22SKatayama Hirofumi MZ     }
2700bfcbda22SKatayama Hirofumi MZ 
2701c94ca812SKatayama Hirofumi MZ     if (PathIsURLW(lpCommand) || UrlIsW(lpCommand, URLIS_APPLIABLE))
2702bfcbda22SKatayama Hirofumi MZ     {
2703bfcbda22SKatayama Hirofumi MZ         StringCchCopyW(szFile, _countof(szFile), lpCommand);
2704bfcbda22SKatayama Hirofumi MZ         pchParams = NULL;
2705bfcbda22SKatayama Hirofumi MZ     }
2706bfcbda22SKatayama Hirofumi MZ     else
2707bfcbda22SKatayama Hirofumi MZ     {
2708f691efefSJose Carlos Jesus         PCWSTR apPathList[2];
2709f691efefSJose Carlos Jesus 
2710bfcbda22SKatayama Hirofumi MZ         pchParams = SplitParams(lpCommand, szFile, _countof(szFile));
2711932a812cSKatayama Hirofumi MZ         if (szFile[0] != UNICODE_NULL && szFile[1] == L':' &&
2712932a812cSKatayama Hirofumi MZ             szFile[2] == UNICODE_NULL)
2713932a812cSKatayama Hirofumi MZ         {
2714932a812cSKatayama Hirofumi MZ             PathAddBackslashW(szFile);
2715932a812cSKatayama Hirofumi MZ         }
2716fc11cf78SKatayama Hirofumi MZ 
2717fc11cf78SKatayama Hirofumi MZ         WCHAR szCurDir[MAX_PATH];
2718fc11cf78SKatayama Hirofumi MZ         GetCurrentDirectoryW(_countof(szCurDir), szCurDir);
2719fc11cf78SKatayama Hirofumi MZ         if (pwszStartDir)
2720fc11cf78SKatayama Hirofumi MZ         {
2721fc11cf78SKatayama Hirofumi MZ             SetCurrentDirectoryW(pwszStartDir);
2722fc11cf78SKatayama Hirofumi MZ         }
2723fc11cf78SKatayama Hirofumi MZ 
2724b40046f4SKatayama Hirofumi MZ         if ((PathIsRelativeW(szFile) &&
2725fc11cf78SKatayama Hirofumi MZ              GetFullPathNameW(szFile, _countof(szFile2), szFile2, NULL) &&
2726b40046f4SKatayama Hirofumi MZ              PathFileExistsW(szFile2)) ||
2727b40046f4SKatayama Hirofumi MZ             SearchPathW(NULL, szFile, NULL, _countof(szFile2), szFile2, NULL))
2728fc11cf78SKatayama Hirofumi MZ         {
2729fc11cf78SKatayama Hirofumi MZ             StringCchCopyW(szFile, _countof(szFile), szFile2);
2730fc11cf78SKatayama Hirofumi MZ         }
2731bfcbda22SKatayama Hirofumi MZ 
2732f691efefSJose Carlos Jesus         apPathList[0] = pwszStartDir;
2733f691efefSJose Carlos Jesus         apPathList[1] = NULL;
2734f691efefSJose Carlos Jesus         PathFindOnPathExW(szFile, apPathList, WHICH_DEFAULT);
2735fc11cf78SKatayama Hirofumi MZ 
2736bfcbda22SKatayama Hirofumi MZ         if (!(dwSeclFlags & SECL_ALLOW_NONEXE))
2737bfcbda22SKatayama Hirofumi MZ         {
2738bfcbda22SKatayama Hirofumi MZ             if (!GetBinaryTypeW(szFile, &dwType))
2739bfcbda22SKatayama Hirofumi MZ             {
2740bfcbda22SKatayama Hirofumi MZ                 SHFree(lpCommand);
2741bfcbda22SKatayama Hirofumi MZ 
2742bfcbda22SKatayama Hirofumi MZ                 if (!(dwSeclFlags & SECL_NO_UI))
2743bfcbda22SKatayama Hirofumi MZ                 {
2744bfcbda22SKatayama Hirofumi MZ                     WCHAR szText[128 + MAX_PATH], szFormat[128];
2745bfcbda22SKatayama Hirofumi MZ                     LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat));
2746bfcbda22SKatayama Hirofumi MZ                     StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
2747bfcbda22SKatayama Hirofumi MZ                     MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
2748bfcbda22SKatayama Hirofumi MZ                 }
2749bfcbda22SKatayama Hirofumi MZ                 return CO_E_APPNOTFOUND;
2750bfcbda22SKatayama Hirofumi MZ             }
2751bfcbda22SKatayama Hirofumi MZ         }
2752bfcbda22SKatayama Hirofumi MZ         else
2753bfcbda22SKatayama Hirofumi MZ         {
2754bfcbda22SKatayama Hirofumi MZ             if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
2755bfcbda22SKatayama Hirofumi MZ             {
2756bfcbda22SKatayama Hirofumi MZ                 SHFree(lpCommand);
2757bfcbda22SKatayama Hirofumi MZ 
2758bfcbda22SKatayama Hirofumi MZ                 if (!(dwSeclFlags & SECL_NO_UI))
2759bfcbda22SKatayama Hirofumi MZ                 {
2760bfcbda22SKatayama Hirofumi MZ                     WCHAR szText[128 + MAX_PATH], szFormat[128];
2761bfcbda22SKatayama Hirofumi MZ                     LoadStringW(shell32_hInstance, IDS_FILE_NOT_FOUND, szFormat, _countof(szFormat));
2762bfcbda22SKatayama Hirofumi MZ                     StringCchPrintfW(szText, _countof(szText), szFormat, szFile);
2763bfcbda22SKatayama Hirofumi MZ                     MessageBoxW(hwnd, szText, NULL, MB_ICONERROR);
2764bfcbda22SKatayama Hirofumi MZ                 }
2765bfcbda22SKatayama Hirofumi MZ                 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
2766bfcbda22SKatayama Hirofumi MZ             }
2767bfcbda22SKatayama Hirofumi MZ         }
2768bfcbda22SKatayama Hirofumi MZ     }
2769bfcbda22SKatayama Hirofumi MZ 
2770bfcbda22SKatayama Hirofumi MZ     ZeroMemory(&info, sizeof(info));
2771bfcbda22SKatayama Hirofumi MZ     info.cbSize = sizeof(info);
2772bfcbda22SKatayama Hirofumi MZ     info.fMask = dwFlags;
2773bfcbda22SKatayama Hirofumi MZ     info.hwnd = hwnd;
2774bfcbda22SKatayama Hirofumi MZ     info.lpVerb = pszVerb;
2775bfcbda22SKatayama Hirofumi MZ     info.lpFile = szFile;
2776bfcbda22SKatayama Hirofumi MZ     info.lpParameters = (pchParams && *pchParams) ? pchParams : NULL;
2777bfcbda22SKatayama Hirofumi MZ     info.lpDirectory = pwszStartDir;
2778bfcbda22SKatayama Hirofumi MZ     info.nShow = nShow;
2779bfcbda22SKatayama Hirofumi MZ     if (ShellExecuteExW(&info))
2780bfcbda22SKatayama Hirofumi MZ     {
2781bfcbda22SKatayama Hirofumi MZ         if (info.lpIDList)
2782bfcbda22SKatayama Hirofumi MZ             CoTaskMemFree(info.lpIDList);
2783bfcbda22SKatayama Hirofumi MZ 
2784bfcbda22SKatayama Hirofumi MZ         SHFree(lpCommand);
2785bfcbda22SKatayama Hirofumi MZ 
2786bfcbda22SKatayama Hirofumi MZ         return S_OK;
2787bfcbda22SKatayama Hirofumi MZ     }
2788bfcbda22SKatayama Hirofumi MZ 
2789bfcbda22SKatayama Hirofumi MZ     dwError = GetLastError();
2790bfcbda22SKatayama Hirofumi MZ 
2791bfcbda22SKatayama Hirofumi MZ     SHFree(lpCommand);
2792bfcbda22SKatayama Hirofumi MZ 
2793bfcbda22SKatayama Hirofumi MZ     return HRESULT_FROM_WIN32(dwError);
2794bfcbda22SKatayama Hirofumi MZ }
279510d9e9deSKatayama Hirofumi MZ 
279610d9e9deSKatayama Hirofumi MZ /*************************************************************************
279710d9e9deSKatayama Hirofumi MZ  *                RealShellExecuteExA (SHELL32.266)
279810d9e9deSKatayama Hirofumi MZ  */
279910d9e9deSKatayama Hirofumi MZ EXTERN_C
280010d9e9deSKatayama Hirofumi MZ 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)280110d9e9deSKatayama Hirofumi MZ RealShellExecuteExA(
280210d9e9deSKatayama Hirofumi MZ     _In_opt_ HWND hwnd,
280310d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpOperation,
280410d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpFile,
280510d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpParameters,
280610d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpDirectory,
280710d9e9deSKatayama Hirofumi MZ     _In_opt_ LPSTR lpReturn,
280810d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpTitle,
280910d9e9deSKatayama Hirofumi MZ     _In_opt_ LPVOID lpReserved,
281010d9e9deSKatayama Hirofumi MZ     _In_ INT nCmdShow,
281110d9e9deSKatayama Hirofumi MZ     _Out_opt_ PHANDLE lphProcess,
281210d9e9deSKatayama Hirofumi MZ     _In_ DWORD dwFlags)
281310d9e9deSKatayama Hirofumi MZ {
281410d9e9deSKatayama Hirofumi MZ     SHELLEXECUTEINFOA ExecInfo;
281510d9e9deSKatayama Hirofumi MZ 
281610d9e9deSKatayama Hirofumi MZ     TRACE("(%p, %s, %s, %s, %s, %p, %s, %p, %u, %p, %lu)\n",
281710d9e9deSKatayama Hirofumi MZ           hwnd, debugstr_a(lpOperation), debugstr_a(lpFile), debugstr_a(lpParameters),
281810d9e9deSKatayama Hirofumi MZ           debugstr_a(lpDirectory), lpReserved, debugstr_a(lpTitle),
281910d9e9deSKatayama Hirofumi MZ           lpReserved, nCmdShow, lphProcess, dwFlags);
282010d9e9deSKatayama Hirofumi MZ 
282110d9e9deSKatayama Hirofumi MZ     ZeroMemory(&ExecInfo, sizeof(ExecInfo));
282210d9e9deSKatayama Hirofumi MZ     ExecInfo.cbSize = sizeof(ExecInfo);
282310d9e9deSKatayama Hirofumi MZ     ExecInfo.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_UNKNOWN_0x1000;
282410d9e9deSKatayama Hirofumi MZ     ExecInfo.hwnd = hwnd;
282510d9e9deSKatayama Hirofumi MZ     ExecInfo.lpVerb = lpOperation;
282610d9e9deSKatayama Hirofumi MZ     ExecInfo.lpFile = lpFile;
282710d9e9deSKatayama Hirofumi MZ     ExecInfo.lpParameters = lpParameters;
282810d9e9deSKatayama Hirofumi MZ     ExecInfo.lpDirectory = lpDirectory;
282910d9e9deSKatayama Hirofumi MZ     ExecInfo.nShow = (WORD)nCmdShow;
283010d9e9deSKatayama Hirofumi MZ 
283110d9e9deSKatayama Hirofumi MZ     if (lpReserved)
283210d9e9deSKatayama Hirofumi MZ     {
283310d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_USE_RESERVED;
283410d9e9deSKatayama Hirofumi MZ         ExecInfo.hInstApp = (HINSTANCE)lpReserved;
283510d9e9deSKatayama Hirofumi MZ     }
283610d9e9deSKatayama Hirofumi MZ 
283710d9e9deSKatayama Hirofumi MZ     if (lpTitle)
283810d9e9deSKatayama Hirofumi MZ     {
283910d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_HASTITLE;
284010d9e9deSKatayama Hirofumi MZ         ExecInfo.lpClass = lpTitle;
284110d9e9deSKatayama Hirofumi MZ     }
284210d9e9deSKatayama Hirofumi MZ 
284310d9e9deSKatayama Hirofumi MZ     if (dwFlags & 1)
284410d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_FLAG_SEPVDM;
284510d9e9deSKatayama Hirofumi MZ 
284610d9e9deSKatayama Hirofumi MZ     if (dwFlags & 2)
284710d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_NO_CONSOLE;
284810d9e9deSKatayama Hirofumi MZ 
284910d9e9deSKatayama Hirofumi MZ     if (lphProcess == NULL)
285010d9e9deSKatayama Hirofumi MZ     {
285110d9e9deSKatayama Hirofumi MZ         ShellExecuteExA(&ExecInfo);
285210d9e9deSKatayama Hirofumi MZ     }
285310d9e9deSKatayama Hirofumi MZ     else
285410d9e9deSKatayama Hirofumi MZ     {
285510d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS;
285610d9e9deSKatayama Hirofumi MZ         ShellExecuteExA(&ExecInfo);
285710d9e9deSKatayama Hirofumi MZ         *lphProcess = ExecInfo.hProcess;
285810d9e9deSKatayama Hirofumi MZ     }
285910d9e9deSKatayama Hirofumi MZ 
286010d9e9deSKatayama Hirofumi MZ     return ExecInfo.hInstApp;
286110d9e9deSKatayama Hirofumi MZ }
286210d9e9deSKatayama Hirofumi MZ 
286310d9e9deSKatayama Hirofumi MZ /*************************************************************************
286410d9e9deSKatayama Hirofumi MZ  *                RealShellExecuteExW (SHELL32.267)
286510d9e9deSKatayama Hirofumi MZ  */
286610d9e9deSKatayama Hirofumi MZ EXTERN_C
286710d9e9deSKatayama Hirofumi MZ 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)286810d9e9deSKatayama Hirofumi MZ RealShellExecuteExW(
286910d9e9deSKatayama Hirofumi MZ     _In_opt_ HWND hwnd,
287010d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpOperation,
287110d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpFile,
287210d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpParameters,
287310d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpDirectory,
287410d9e9deSKatayama Hirofumi MZ     _In_opt_ LPWSTR lpReturn,
287510d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpTitle,
287610d9e9deSKatayama Hirofumi MZ     _In_opt_ LPVOID lpReserved,
287710d9e9deSKatayama Hirofumi MZ     _In_ INT nCmdShow,
287810d9e9deSKatayama Hirofumi MZ     _Out_opt_ PHANDLE lphProcess,
287910d9e9deSKatayama Hirofumi MZ     _In_ DWORD dwFlags)
288010d9e9deSKatayama Hirofumi MZ {
288110d9e9deSKatayama Hirofumi MZ     SHELLEXECUTEINFOW ExecInfo;
288210d9e9deSKatayama Hirofumi MZ 
288310d9e9deSKatayama Hirofumi MZ     TRACE("(%p, %s, %s, %s, %s, %p, %s, %p, %u, %p, %lu)\n",
288410d9e9deSKatayama Hirofumi MZ           hwnd, debugstr_w(lpOperation), debugstr_w(lpFile), debugstr_w(lpParameters),
288510d9e9deSKatayama Hirofumi MZ           debugstr_w(lpDirectory), lpReserved, debugstr_w(lpTitle),
288610d9e9deSKatayama Hirofumi MZ           lpReserved, nCmdShow, lphProcess, dwFlags);
288710d9e9deSKatayama Hirofumi MZ 
288810d9e9deSKatayama Hirofumi MZ     ZeroMemory(&ExecInfo, sizeof(ExecInfo));
288910d9e9deSKatayama Hirofumi MZ     ExecInfo.cbSize = sizeof(ExecInfo);
289010d9e9deSKatayama Hirofumi MZ     ExecInfo.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_UNKNOWN_0x1000;
289110d9e9deSKatayama Hirofumi MZ     ExecInfo.hwnd = hwnd;
289210d9e9deSKatayama Hirofumi MZ     ExecInfo.lpVerb = lpOperation;
289310d9e9deSKatayama Hirofumi MZ     ExecInfo.lpFile = lpFile;
289410d9e9deSKatayama Hirofumi MZ     ExecInfo.lpParameters = lpParameters;
289510d9e9deSKatayama Hirofumi MZ     ExecInfo.lpDirectory = lpDirectory;
289610d9e9deSKatayama Hirofumi MZ     ExecInfo.nShow = (WORD)nCmdShow;
289710d9e9deSKatayama Hirofumi MZ 
289810d9e9deSKatayama Hirofumi MZ     if (lpReserved)
289910d9e9deSKatayama Hirofumi MZ     {
290010d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_USE_RESERVED;
290110d9e9deSKatayama Hirofumi MZ         ExecInfo.hInstApp = (HINSTANCE)lpReserved;
290210d9e9deSKatayama Hirofumi MZ     }
290310d9e9deSKatayama Hirofumi MZ 
290410d9e9deSKatayama Hirofumi MZ     if (lpTitle)
290510d9e9deSKatayama Hirofumi MZ     {
290610d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_HASTITLE;
290710d9e9deSKatayama Hirofumi MZ         ExecInfo.lpClass = lpTitle;
290810d9e9deSKatayama Hirofumi MZ     }
290910d9e9deSKatayama Hirofumi MZ 
291010d9e9deSKatayama Hirofumi MZ     if (dwFlags & 1)
291110d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_FLAG_SEPVDM;
291210d9e9deSKatayama Hirofumi MZ 
291310d9e9deSKatayama Hirofumi MZ     if (dwFlags & 2)
291410d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_NO_CONSOLE;
291510d9e9deSKatayama Hirofumi MZ 
291610d9e9deSKatayama Hirofumi MZ     if (lphProcess == NULL)
291710d9e9deSKatayama Hirofumi MZ     {
291810d9e9deSKatayama Hirofumi MZ         ShellExecuteExW(&ExecInfo);
291910d9e9deSKatayama Hirofumi MZ     }
292010d9e9deSKatayama Hirofumi MZ     else
292110d9e9deSKatayama Hirofumi MZ     {
292210d9e9deSKatayama Hirofumi MZ         ExecInfo.fMask |= SEE_MASK_NOCLOSEPROCESS;
292310d9e9deSKatayama Hirofumi MZ         ShellExecuteExW(&ExecInfo);
292410d9e9deSKatayama Hirofumi MZ         *lphProcess = ExecInfo.hProcess;
292510d9e9deSKatayama Hirofumi MZ     }
292610d9e9deSKatayama Hirofumi MZ 
292710d9e9deSKatayama Hirofumi MZ     return ExecInfo.hInstApp;
292810d9e9deSKatayama Hirofumi MZ }
292910d9e9deSKatayama Hirofumi MZ 
293010d9e9deSKatayama Hirofumi MZ /*************************************************************************
293110d9e9deSKatayama Hirofumi MZ  *                RealShellExecuteA (SHELL32.265)
293210d9e9deSKatayama Hirofumi MZ  */
293310d9e9deSKatayama Hirofumi MZ EXTERN_C
293410d9e9deSKatayama Hirofumi MZ 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)293510d9e9deSKatayama Hirofumi MZ RealShellExecuteA(
293610d9e9deSKatayama Hirofumi MZ     _In_opt_ HWND hwnd,
293710d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpOperation,
293810d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpFile,
293910d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpParameters,
294010d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpDirectory,
294110d9e9deSKatayama Hirofumi MZ     _In_opt_ LPSTR lpReturn,
294210d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCSTR lpTitle,
294310d9e9deSKatayama Hirofumi MZ     _In_opt_ LPVOID lpReserved,
294410d9e9deSKatayama Hirofumi MZ     _In_ INT nCmdShow,
294510d9e9deSKatayama Hirofumi MZ     _Out_opt_ PHANDLE lphProcess)
294610d9e9deSKatayama Hirofumi MZ {
294710d9e9deSKatayama Hirofumi MZ     return RealShellExecuteExA(hwnd,
294810d9e9deSKatayama Hirofumi MZ                                lpOperation,
294910d9e9deSKatayama Hirofumi MZ                                lpFile,
295010d9e9deSKatayama Hirofumi MZ                                lpParameters,
295110d9e9deSKatayama Hirofumi MZ                                lpDirectory,
295210d9e9deSKatayama Hirofumi MZ                                lpReturn,
295310d9e9deSKatayama Hirofumi MZ                                lpTitle,
295410d9e9deSKatayama Hirofumi MZ                                lpReserved,
295510d9e9deSKatayama Hirofumi MZ                                nCmdShow,
295610d9e9deSKatayama Hirofumi MZ                                lphProcess,
295710d9e9deSKatayama Hirofumi MZ                                0);
295810d9e9deSKatayama Hirofumi MZ }
295910d9e9deSKatayama Hirofumi MZ 
296010d9e9deSKatayama Hirofumi MZ /*************************************************************************
296110d9e9deSKatayama Hirofumi MZ  *                RealShellExecuteW (SHELL32.268)
296210d9e9deSKatayama Hirofumi MZ  */
296310d9e9deSKatayama Hirofumi MZ EXTERN_C
296410d9e9deSKatayama Hirofumi MZ 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)296510d9e9deSKatayama Hirofumi MZ RealShellExecuteW(
296610d9e9deSKatayama Hirofumi MZ     _In_opt_ HWND hwnd,
296710d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpOperation,
296810d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpFile,
296910d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpParameters,
297010d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpDirectory,
297110d9e9deSKatayama Hirofumi MZ     _In_opt_ LPWSTR lpReturn,
297210d9e9deSKatayama Hirofumi MZ     _In_opt_ LPCWSTR lpTitle,
297310d9e9deSKatayama Hirofumi MZ     _In_opt_ LPVOID lpReserved,
297410d9e9deSKatayama Hirofumi MZ     _In_ INT nCmdShow,
297510d9e9deSKatayama Hirofumi MZ     _Out_opt_ PHANDLE lphProcess)
297610d9e9deSKatayama Hirofumi MZ {
297710d9e9deSKatayama Hirofumi MZ     return RealShellExecuteExW(hwnd,
297810d9e9deSKatayama Hirofumi MZ                                lpOperation,
297910d9e9deSKatayama Hirofumi MZ                                lpFile,
298010d9e9deSKatayama Hirofumi MZ                                lpParameters,
298110d9e9deSKatayama Hirofumi MZ                                lpDirectory,
298210d9e9deSKatayama Hirofumi MZ                                lpReturn,
298310d9e9deSKatayama Hirofumi MZ                                lpTitle,
298410d9e9deSKatayama Hirofumi MZ                                lpReserved,
298510d9e9deSKatayama Hirofumi MZ                                nCmdShow,
298610d9e9deSKatayama Hirofumi MZ                                lphProcess,
298710d9e9deSKatayama Hirofumi MZ                                0);
298810d9e9deSKatayama Hirofumi MZ }
2989*dad3a093SKatayama Hirofumi MZ 
2990*dad3a093SKatayama Hirofumi MZ // The common helper of ShellExec_RunDLLA and ShellExec_RunDLLW
2991*dad3a093SKatayama Hirofumi MZ static VOID
ShellExec_RunDLL_Helper(_In_opt_ HWND hwnd,_In_opt_ HINSTANCE hInstance,_In_ PCWSTR pszCmdLine,_In_ INT nCmdShow)2992*dad3a093SKatayama Hirofumi MZ ShellExec_RunDLL_Helper(
2993*dad3a093SKatayama Hirofumi MZ     _In_opt_ HWND hwnd,
2994*dad3a093SKatayama Hirofumi MZ     _In_opt_ HINSTANCE hInstance,
2995*dad3a093SKatayama Hirofumi MZ     _In_ PCWSTR pszCmdLine,
2996*dad3a093SKatayama Hirofumi MZ     _In_ INT nCmdShow)
2997*dad3a093SKatayama Hirofumi MZ {
2998*dad3a093SKatayama Hirofumi MZ     TRACE("(%p, %p, %s, 0x%X)\n", hwnd, hInstance, wine_dbgstr_w(pszCmdLine), nCmdShow);
2999*dad3a093SKatayama Hirofumi MZ 
3000*dad3a093SKatayama Hirofumi MZ     if (!pszCmdLine || !*pszCmdLine)
3001*dad3a093SKatayama Hirofumi MZ         return;
3002*dad3a093SKatayama Hirofumi MZ 
3003*dad3a093SKatayama Hirofumi MZ     // '?' enables us to specify the additional mask value
3004*dad3a093SKatayama Hirofumi MZ     ULONG fNewMask = SEE_MASK_NOASYNC;
3005*dad3a093SKatayama Hirofumi MZ     if (*pszCmdLine == L'?') // 1st question
3006*dad3a093SKatayama Hirofumi MZ     {
3007*dad3a093SKatayama Hirofumi MZ         INT MaskValue;
3008*dad3a093SKatayama Hirofumi MZ         if (StrToIntExW(pszCmdLine + 1, STIF_SUPPORT_HEX, &MaskValue))
3009*dad3a093SKatayama Hirofumi MZ             fNewMask |= MaskValue;
3010*dad3a093SKatayama Hirofumi MZ 
3011*dad3a093SKatayama Hirofumi MZ         PCWSTR pch2ndQuestion = StrChrW(pszCmdLine + 1, L'?'); // 2nd question
3012*dad3a093SKatayama Hirofumi MZ         if (pch2ndQuestion)
3013*dad3a093SKatayama Hirofumi MZ             pszCmdLine = pch2ndQuestion + 1;
3014*dad3a093SKatayama Hirofumi MZ     }
3015*dad3a093SKatayama Hirofumi MZ 
3016*dad3a093SKatayama Hirofumi MZ     WCHAR szPath[2 * MAX_PATH];
3017*dad3a093SKatayama Hirofumi MZ     if (PathProcessCommandAW(pszCmdLine, szPath, _countof(szPath), L'C') == -1)
3018*dad3a093SKatayama Hirofumi MZ         StrCpyNW(szPath, pszCmdLine, _countof(szPath));
3019*dad3a093SKatayama Hirofumi MZ 
3020*dad3a093SKatayama Hirofumi MZ     // Split arguments from the path
3021*dad3a093SKatayama Hirofumi MZ     LPWSTR Args = PathGetArgsW(szPath);
3022*dad3a093SKatayama Hirofumi MZ     if (*Args)
3023*dad3a093SKatayama Hirofumi MZ         *(Args - 1) = UNICODE_NULL;
3024*dad3a093SKatayama Hirofumi MZ 
3025*dad3a093SKatayama Hirofumi MZ     PathUnquoteSpacesW(szPath);
3026*dad3a093SKatayama Hirofumi MZ 
3027*dad3a093SKatayama Hirofumi MZ     // Execute
3028*dad3a093SKatayama Hirofumi MZ     SHELLEXECUTEINFOW execInfo = { sizeof(execInfo) };
3029*dad3a093SKatayama Hirofumi MZ     execInfo.fMask = fNewMask;
3030*dad3a093SKatayama Hirofumi MZ     execInfo.hwnd = hwnd;
3031*dad3a093SKatayama Hirofumi MZ     execInfo.lpFile = szPath;
3032*dad3a093SKatayama Hirofumi MZ     execInfo.lpParameters = Args;
3033*dad3a093SKatayama Hirofumi MZ     execInfo.nShow = nCmdShow;
3034*dad3a093SKatayama Hirofumi MZ     if (!ShellExecuteExW(&execInfo))
3035*dad3a093SKatayama Hirofumi MZ     {
3036*dad3a093SKatayama Hirofumi MZ         DWORD dwError = GetLastError();
3037*dad3a093SKatayama Hirofumi MZ         if (SHELL_InRunDllProcess()) // Is it a RUNDLL process?
3038*dad3a093SKatayama Hirofumi MZ             ExitProcess(dwError); // Terminate it now
3039*dad3a093SKatayama Hirofumi MZ     }
3040*dad3a093SKatayama Hirofumi MZ }
3041*dad3a093SKatayama Hirofumi MZ 
3042*dad3a093SKatayama Hirofumi MZ /*************************************************************************
3043*dad3a093SKatayama Hirofumi MZ  *  ShellExec_RunDLLA [SHELL32.358]
3044*dad3a093SKatayama Hirofumi MZ  *
3045*dad3a093SKatayama Hirofumi MZ  * @see https://www.hexacorn.com/blog/2024/11/30/1-little-known-secret-of-shellexec_rundll/
3046*dad3a093SKatayama Hirofumi MZ  */
3047*dad3a093SKatayama Hirofumi MZ EXTERN_C
3048*dad3a093SKatayama Hirofumi MZ VOID WINAPI
ShellExec_RunDLLA(_In_opt_ HWND hwnd,_In_opt_ HINSTANCE hInstance,_In_ PCSTR pszCmdLine,_In_ INT nCmdShow)3049*dad3a093SKatayama Hirofumi MZ ShellExec_RunDLLA(
3050*dad3a093SKatayama Hirofumi MZ     _In_opt_ HWND hwnd,
3051*dad3a093SKatayama Hirofumi MZ     _In_opt_ HINSTANCE hInstance,
3052*dad3a093SKatayama Hirofumi MZ     _In_ PCSTR pszCmdLine,
3053*dad3a093SKatayama Hirofumi MZ     _In_ INT nCmdShow)
3054*dad3a093SKatayama Hirofumi MZ {
3055*dad3a093SKatayama Hirofumi MZ     CStringW strCmdLine = pszCmdLine; // Keep
3056*dad3a093SKatayama Hirofumi MZ     ShellExec_RunDLL_Helper(hwnd, hInstance, strCmdLine, nCmdShow);
3057*dad3a093SKatayama Hirofumi MZ }
3058*dad3a093SKatayama Hirofumi MZ 
3059*dad3a093SKatayama Hirofumi MZ /*************************************************************************
3060*dad3a093SKatayama Hirofumi MZ  *  ShellExec_RunDLLW [SHELL32.359]
3061*dad3a093SKatayama Hirofumi MZ  *
3062*dad3a093SKatayama Hirofumi MZ  * @see https://www.hexacorn.com/blog/2024/11/30/1-little-known-secret-of-shellexec_rundll/
3063*dad3a093SKatayama Hirofumi MZ  */
3064*dad3a093SKatayama Hirofumi MZ EXTERN_C
3065*dad3a093SKatayama Hirofumi MZ VOID WINAPI
ShellExec_RunDLLW(_In_opt_ HWND hwnd,_In_opt_ HINSTANCE hInstance,_In_ PCWSTR pszCmdLine,_In_ INT nCmdShow)3066*dad3a093SKatayama Hirofumi MZ ShellExec_RunDLLW(
3067*dad3a093SKatayama Hirofumi MZ     _In_opt_ HWND hwnd,
3068*dad3a093SKatayama Hirofumi MZ     _In_opt_ HINSTANCE hInstance,
3069*dad3a093SKatayama Hirofumi MZ     _In_ PCWSTR pszCmdLine,
3070*dad3a093SKatayama Hirofumi MZ     _In_ INT nCmdShow)
3071*dad3a093SKatayama Hirofumi MZ {
3072*dad3a093SKatayama Hirofumi MZ     ShellExec_RunDLL_Helper(hwnd, hInstance, pszCmdLine, nCmdShow);
3073*dad3a093SKatayama Hirofumi MZ }
3074