2 * Unit test of the ShellExecute function.
4 * Copyright 2005 Francois Gouget for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * - test the default verb selection
23 * - test selection of an alternate class
24 * - try running executables in more ways
25 * - try passing arguments to executables
26 * - ShellExecute("foo.shlexec") with no path should work if foo.shlexec is
28 * - test associations that use %l, %L or "%1" instead of %1
29 * - we may want to test ShellExecuteEx() instead of ShellExecute()
30 * and then we could also check its return value
31 * - ShellExecuteEx() also calls SetLastError() with meaningful values which
35 /* Needed to get SEE_MASK_NOZONECHECKS with the PSDK */
36 #define NTDDI_WINXPSP1 0x05010100
37 #define NTDDI_VERSION NTDDI_WINXPSP1
38 #define _WIN32_WINNT 0x0501
48 #include "wine/test.h"
50 #include "shell32_test.h"
53 static char argv0
[MAX_PATH
];
56 static char tmpdir
[MAX_PATH
];
57 static char child_file
[MAX_PATH
];
58 static DLLVERSIONINFO dllver
;
59 static BOOL skip_noassoc_tests
= FALSE
;
60 static HANDLE dde_ready_event
;
65 * ShellExecute wrappers
68 static void dump_child(void);
71 static void init_event(const char* child_file
)
74 event_name
=strrchr(child_file
, '\\')+1;
75 hEvent
=CreateEvent(NULL
, FALSE
, FALSE
, event_name
);
78 static void strcat_param(char* str
, const char* param
)
92 static char shell_call
[2048]="";
93 static int shell_execute(LPCSTR operation
, LPCSTR file
, LPCSTR parameters
, LPCSTR directory
)
95 INT_PTR rc
, rcEmpty
= 0;
98 rcEmpty
= shell_execute("", file
, parameters
, directory
);
100 strcpy(shell_call
, "ShellExecute(");
101 strcat_param(shell_call
, operation
);
102 strcat(shell_call
, ", ");
103 strcat_param(shell_call
, file
);
104 strcat(shell_call
, ", ");
105 strcat_param(shell_call
, parameters
);
106 strcat(shell_call
, ", ");
107 strcat_param(shell_call
, directory
);
108 strcat(shell_call
, ")");
109 if (winetest_debug
> 1)
110 trace("%s\n", shell_call
);
112 DeleteFile(child_file
);
113 SetLastError(0xcafebabe);
115 /* FIXME: We cannot use ShellExecuteEx() here because if there is no
116 * association it displays the 'Open With' dialog and I could not find
117 * a flag to prevent this.
119 rc
=(INT_PTR
)ShellExecute(NULL
, operation
, file
, parameters
, directory
, SW_SHOWNORMAL
);
124 wait_rc
=WaitForSingleObject(hEvent
, 5000);
125 if (wait_rc
== WAIT_TIMEOUT
)
127 HWND wnd
= FindWindowA("#32770", "Windows");
130 SendMessage(wnd
, WM_CLOSE
, 0, 0);
131 win_skip("Skipping shellexecute of file with unassociated extension\n");
132 skip_noassoc_tests
= TRUE
;
136 ok(wait_rc
==WAIT_OBJECT_0
|| rc
<= 32, "WaitForSingleObject returned %d\n", wait_rc
);
138 /* The child process may have changed the result file, so let profile
139 * functions know about it
141 WritePrivateProfileStringA(NULL
, NULL
, NULL
, child_file
);
146 ok(rc
== rcEmpty
|| broken(rc
> 32 && rcEmpty
== SE_ERR_NOASSOC
) /* NT4 */,
147 "Got different return value with empty string: %lu %lu\n", rc
, rcEmpty
);
152 static int shell_execute_ex(DWORD mask
, LPCSTR operation
, LPCSTR file
,
153 LPCSTR parameters
, LPCSTR directory
)
155 SHELLEXECUTEINFO sei
;
159 strcpy(shell_call
, "ShellExecuteEx(");
160 strcat_param(shell_call
, operation
);
161 strcat(shell_call
, ", ");
162 strcat_param(shell_call
, file
);
163 strcat(shell_call
, ", ");
164 strcat_param(shell_call
, parameters
);
165 strcat(shell_call
, ", ");
166 strcat_param(shell_call
, directory
);
167 strcat(shell_call
, ")");
168 if (winetest_debug
> 1)
169 trace("%s\n", shell_call
);
171 sei
.cbSize
=sizeof(sei
);
172 sei
.fMask
=SEE_MASK_NOCLOSEPROCESS
| mask
;
174 sei
.lpVerb
=operation
;
176 sei
.lpParameters
=parameters
;
177 sei
.lpDirectory
=directory
;
178 sei
.nShow
=SW_SHOWNORMAL
;
179 sei
.hInstApp
=NULL
; /* Out */
185 sei
.hProcess
=NULL
; /* Out */
187 DeleteFile(child_file
);
188 SetLastError(0xcafebabe);
189 success
=ShellExecuteEx(&sei
);
190 rc
=(INT_PTR
)sei
.hInstApp
;
191 ok((success
&& rc
> 32) || (!success
&& rc
<= 32),
192 "%s rc=%d and hInstApp=%ld is not allowed\n", shell_call
, success
, rc
);
197 if (sei
.hProcess
!=NULL
)
199 wait_rc
=WaitForSingleObject(sei
.hProcess
, 5000);
200 ok(wait_rc
==WAIT_OBJECT_0
, "WaitForSingleObject(hProcess) returned %d\n", wait_rc
);
202 wait_rc
=WaitForSingleObject(hEvent
, 5000);
203 ok(wait_rc
==WAIT_OBJECT_0
, "WaitForSingleObject returned %d\n", wait_rc
);
205 /* The child process may have changed the result file, so let profile
206 * functions know about it
208 WritePrivateProfileStringA(NULL
, NULL
, NULL
, child_file
);
219 * Functions to create / delete associations wrappers
223 static BOOL
create_test_association(const char* extension
)
225 HKEY hkey
, hkey_shell
;
226 char class[MAX_PATH
];
229 sprintf(class, "shlexec%s", extension
);
230 rc
=RegCreateKeyEx(HKEY_CLASSES_ROOT
, extension
, 0, NULL
, 0, KEY_SET_VALUE
,
232 if (rc
!= ERROR_SUCCESS
)
235 rc
=RegSetValueEx(hkey
, NULL
, 0, REG_SZ
, (LPBYTE
) class, strlen(class)+1);
236 ok(rc
==ERROR_SUCCESS
, "RegSetValueEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc
);
239 rc
=RegCreateKeyEx(HKEY_CLASSES_ROOT
, class, 0, NULL
, 0,
240 KEY_CREATE_SUB_KEY
| KEY_ENUMERATE_SUB_KEYS
, NULL
, &hkey
, NULL
);
241 ok(rc
==ERROR_SUCCESS
, "RegCreateKeyEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc
);
243 rc
=RegCreateKeyEx(hkey
, "shell", 0, NULL
, 0,
244 KEY_CREATE_SUB_KEY
, NULL
, &hkey_shell
, NULL
);
245 ok(rc
==ERROR_SUCCESS
, "RegCreateKeyEx 'shell' failed, expected ERROR_SUCCESS, got %d\n", rc
);
248 CloseHandle(hkey_shell
);
253 /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */
254 static LSTATUS
myRegDeleteTreeA(HKEY hKey
, LPCSTR lpszSubKey
)
257 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
258 DWORD dwMaxLen
, dwSize
;
259 CHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
264 ret
= RegOpenKeyExA(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
268 /* Get highest length for keys, values */
269 ret
= RegQueryInfoKeyA(hSubKey
, NULL
, NULL
, NULL
, NULL
,
270 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
271 if (ret
) goto cleanup
;
275 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
276 if (dwMaxLen
> sizeof(szNameBuf
)/sizeof(CHAR
))
278 /* Name too big: alloc a buffer for it */
279 if (!(lpszName
= HeapAlloc( GetProcessHeap(), 0, dwMaxLen
*sizeof(CHAR
))))
281 ret
= ERROR_NOT_ENOUGH_MEMORY
;
287 /* Recursively delete all the subkeys */
291 if (RegEnumKeyExA(hSubKey
, 0, lpszName
, &dwSize
, NULL
,
292 NULL
, NULL
, NULL
)) break;
294 ret
= myRegDeleteTreeA(hSubKey
, lpszName
);
295 if (ret
) goto cleanup
;
299 ret
= RegDeleteKeyA(hKey
, lpszSubKey
);
304 if (RegEnumValueA(hKey
, 0, lpszName
, &dwSize
,
305 NULL
, NULL
, NULL
, NULL
)) break;
307 ret
= RegDeleteValueA(hKey
, lpszName
);
308 if (ret
) goto cleanup
;
312 /* Free buffer if allocated */
313 if (lpszName
!= szNameBuf
)
314 HeapFree( GetProcessHeap(), 0, lpszName
);
316 RegCloseKey(hSubKey
);
320 static void delete_test_association(const char* extension
)
322 char class[MAX_PATH
];
324 sprintf(class, "shlexec%s", extension
);
325 myRegDeleteTreeA(HKEY_CLASSES_ROOT
, class);
326 myRegDeleteTreeA(HKEY_CLASSES_ROOT
, extension
);
329 static void create_test_verb_dde(const char* extension
, const char* verb
,
330 int rawcmd
, const char* cmdtail
, const char *ddeexec
,
331 const char *application
, const char *topic
,
334 HKEY hkey_shell
, hkey_verb
, hkey_cmd
;
335 char shell
[MAX_PATH
];
339 sprintf(shell
, "shlexec%s\\shell", extension
);
340 rc
=RegOpenKeyEx(HKEY_CLASSES_ROOT
, shell
, 0,
341 KEY_CREATE_SUB_KEY
, &hkey_shell
);
342 assert(rc
==ERROR_SUCCESS
);
343 rc
=RegCreateKeyEx(hkey_shell
, verb
, 0, NULL
, 0, KEY_CREATE_SUB_KEY
,
344 NULL
, &hkey_verb
, NULL
);
345 assert(rc
==ERROR_SUCCESS
);
346 rc
=RegCreateKeyEx(hkey_verb
, "command", 0, NULL
, 0, KEY_SET_VALUE
,
347 NULL
, &hkey_cmd
, NULL
);
348 assert(rc
==ERROR_SUCCESS
);
352 rc
=RegSetValueEx(hkey_cmd
, NULL
, 0, REG_SZ
, (LPBYTE
)cmdtail
, strlen(cmdtail
)+1);
356 cmd
=HeapAlloc(GetProcessHeap(), 0, strlen(argv0
)+10+strlen(child_file
)+2+strlen(cmdtail
)+1);
357 sprintf(cmd
,"%s shlexec \"%s\" %s", argv0
, child_file
, cmdtail
);
358 rc
=RegSetValueEx(hkey_cmd
, NULL
, 0, REG_SZ
, (LPBYTE
)cmd
, strlen(cmd
)+1);
359 assert(rc
==ERROR_SUCCESS
);
360 HeapFree(GetProcessHeap(), 0, cmd
);
365 HKEY hkey_ddeexec
, hkey_application
, hkey_topic
, hkey_ifexec
;
367 rc
=RegCreateKeyEx(hkey_verb
, "ddeexec", 0, NULL
, 0, KEY_SET_VALUE
|
368 KEY_CREATE_SUB_KEY
, NULL
, &hkey_ddeexec
, NULL
);
369 assert(rc
==ERROR_SUCCESS
);
370 rc
=RegSetValueEx(hkey_ddeexec
, NULL
, 0, REG_SZ
, (LPBYTE
)ddeexec
,
372 assert(rc
==ERROR_SUCCESS
);
375 rc
=RegCreateKeyEx(hkey_ddeexec
, "application", 0, NULL
, 0, KEY_SET_VALUE
,
376 NULL
, &hkey_application
, NULL
);
377 assert(rc
==ERROR_SUCCESS
);
378 rc
=RegSetValueEx(hkey_application
, NULL
, 0, REG_SZ
, (LPBYTE
)application
,
379 strlen(application
)+1);
380 assert(rc
==ERROR_SUCCESS
);
381 CloseHandle(hkey_application
);
385 rc
=RegCreateKeyEx(hkey_ddeexec
, "topic", 0, NULL
, 0, KEY_SET_VALUE
,
386 NULL
, &hkey_topic
, NULL
);
387 assert(rc
==ERROR_SUCCESS
);
388 rc
=RegSetValueEx(hkey_topic
, NULL
, 0, REG_SZ
, (LPBYTE
)topic
,
390 assert(rc
==ERROR_SUCCESS
);
391 CloseHandle(hkey_topic
);
395 rc
=RegCreateKeyEx(hkey_ddeexec
, "ifexec", 0, NULL
, 0, KEY_SET_VALUE
,
396 NULL
, &hkey_ifexec
, NULL
);
397 assert(rc
==ERROR_SUCCESS
);
398 rc
=RegSetValueEx(hkey_ifexec
, NULL
, 0, REG_SZ
, (LPBYTE
)ifexec
,
400 assert(rc
==ERROR_SUCCESS
);
401 CloseHandle(hkey_ifexec
);
403 CloseHandle(hkey_ddeexec
);
406 CloseHandle(hkey_shell
);
407 CloseHandle(hkey_verb
);
408 CloseHandle(hkey_cmd
);
411 static void create_test_verb(const char* extension
, const char* verb
,
412 int rawcmd
, const char* cmdtail
)
414 create_test_verb_dde(extension
, verb
, rawcmd
, cmdtail
, NULL
, NULL
,
420 * Functions to check that the child process was started just right
421 * (borrowed from dlls/kernel32/tests/process.c)
425 static const char* encodeA(const char* str
)
427 static char encoded
[2*1024+1];
432 len
= strlen(str
) + 1;
433 if (len
>= sizeof(encoded
)/2)
435 fprintf(stderr
, "string is too long!\n");
439 for (i
= 0; i
< len
; i
++)
440 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
445 static unsigned decode_char(char c
)
447 if (c
>= '0' && c
<= '9') return c
- '0';
448 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
449 assert(c
>= 'A' && c
<= 'F');
453 static char* decodeA(const char* str
)
455 static char decoded
[1024];
459 len
= strlen(str
) / 2;
460 if (!len
--) return NULL
;
461 if (len
>= sizeof(decoded
))
463 fprintf(stderr
, "string is too long!\n");
467 for (i
= 0; i
< len
; i
++)
468 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
473 static void childPrintf(HANDLE h
, const char* fmt
, ...)
479 va_start(valist
, fmt
);
480 vsprintf(buffer
, fmt
, valist
);
482 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
485 static DWORD ddeInst
;
487 static char ddeExec
[MAX_PATH
], ddeApplication
[MAX_PATH
];
488 static BOOL post_quit_on_execute
;
490 static HDDEDATA CALLBACK
ddeCb(UINT uType
, UINT uFmt
, HCONV hConv
,
491 HSZ hsz1
, HSZ hsz2
, HDDEDATA hData
,
492 ULONG_PTR dwData1
, ULONG_PTR dwData2
)
496 if (winetest_debug
> 2)
497 trace("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
498 uType
, uFmt
, hConv
, hsz1
, hsz2
, hData
, dwData1
, dwData2
);
503 if (!DdeCmpStringHandles(hsz1
, hszTopic
))
505 size
= DdeQueryString(ddeInst
, hsz2
, ddeApplication
, MAX_PATH
, CP_WINANSI
);
506 assert(size
< MAX_PATH
);
507 return (HDDEDATA
)TRUE
;
509 return (HDDEDATA
)FALSE
;
512 size
= DdeGetData(hData
, (LPBYTE
)ddeExec
, MAX_PATH
, 0L);
513 assert(size
< MAX_PATH
);
514 DdeFreeDataHandle(hData
);
515 if (post_quit_on_execute
)
517 return (HDDEDATA
)DDE_FACK
;
525 * This is just to make sure the child won't run forever stuck in a GetMessage()
526 * loop when DDE fails for some reason.
528 static void CALLBACK
childTimeout(HWND wnd
, UINT msg
, UINT_PTR timer
, DWORD time
)
530 trace("childTimeout called\n");
535 static void doChild(int argc
, char** argv
)
537 char *filename
, longpath
[MAX_PATH
] = "";
548 hFile
=CreateFileA(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
549 if (hFile
== INVALID_HANDLE_VALUE
)
553 childPrintf(hFile
, "[Arguments]\r\n");
554 if (winetest_debug
> 2)
555 trace("argcA=%d\n", argc
);
556 childPrintf(hFile
, "argcA=%d\r\n", argc
);
557 for (i
= 0; i
< argc
; i
++)
559 if (winetest_debug
> 2)
560 trace("argvA%d=%s\n", i
, argv
[i
]);
561 childPrintf(hFile
, "argvA%d=%s\r\n", i
, encodeA(argv
[i
]));
563 GetModuleFileNameA(GetModuleHandleA(NULL
), longpath
, MAX_PATH
);
564 childPrintf(hFile
, "longPath=%s\r\n", encodeA(longpath
));
566 map
= OpenFileMappingA(FILE_MAP_READ
, FALSE
, "winetest_shlexec_dde_map");
569 shared_block
= MapViewOfFile(map
, FILE_MAP_READ
, 0, 0, 4096);
571 if (shared_block
[0] != '\0' || shared_block
[1] != '\0')
573 post_quit_on_execute
= TRUE
;
575 rc
= DdeInitializeA(&ddeInst
, ddeCb
, CBF_SKIP_ALLNOTIFICATIONS
| CBF_FAIL_ADVISES
|
576 CBF_FAIL_POKES
| CBF_FAIL_REQUESTS
, 0L);
577 assert(rc
== DMLERR_NO_ERROR
);
578 hszApplication
= DdeCreateStringHandleA(ddeInst
, shared_block
, CP_WINANSI
);
579 hszTopic
= DdeCreateStringHandleA(ddeInst
, shared_block
+ strlen(shared_block
) + 1, CP_WINANSI
);
580 assert(hszApplication
&& hszTopic
);
581 assert(DdeNameService(ddeInst
, hszApplication
, 0L, DNS_REGISTER
| DNS_FILTEROFF
));
583 timer
= SetTimer(NULL
, 0, 2500, childTimeout
);
585 dde_ready
= OpenEvent(EVENT_MODIFY_STATE
, FALSE
, "winetest_shlexec_dde_ready");
587 CloseHandle(dde_ready
);
589 while (GetMessage(&msg
, NULL
, 0, 0))
590 DispatchMessage(&msg
);
593 KillTimer(NULL
, timer
);
594 assert(DdeNameService(ddeInst
, hszApplication
, 0L, DNS_UNREGISTER
));
595 assert(DdeFreeStringHandle(ddeInst
, hszTopic
));
596 assert(DdeFreeStringHandle(ddeInst
, hszApplication
));
597 assert(DdeUninitialize(ddeInst
));
601 dde_ready
= OpenEvent(EVENT_MODIFY_STATE
, FALSE
, "winetest_shlexec_dde_ready");
603 CloseHandle(dde_ready
);
606 UnmapViewOfFile(shared_block
);
608 childPrintf(hFile
, "ddeExec=%s\r\n", encodeA(ddeExec
));
613 init_event(filename
);
618 static char* getChildString(const char* sect
, const char* key
)
623 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), child_file
);
624 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
625 assert(!(strlen(buf
) & 1));
630 static void dump_child(void)
632 if (winetest_debug
> 1)
638 c
=GetPrivateProfileIntA("Arguments", "argcA", -1, child_file
);
639 trace("argcA=%d\n",c
);
642 sprintf(key
, "argvA%d", i
);
643 str
=getChildString("Arguments", key
);
644 trace("%s=%s\n", key
, str
);
649 static int StrCmpPath(const char* s1
, const char* s2
)
651 if (!s1
&& !s2
) return 0;
662 if ((*s1
=='/' || *s1
=='\\') && (*s2
=='/' || *s2
=='\\'))
664 while (*s1
=='/' || *s1
=='\\')
666 while (*s2
=='/' || *s2
=='\\')
669 else if (toupper(*s1
)==toupper(*s2
))
686 static void _okChildString(const char* file
, int line
, const char* key
, const char* expected
)
689 result
=getChildString("Arguments", key
);
692 ok_(file
, line
)(FALSE
, "%s expected '%s', but key not found or empty\n", key
, expected
);
695 ok_(file
, line
)(lstrcmpiA(result
, expected
) == 0,
696 "%s expected '%s', got '%s'\n", key
, expected
, result
);
699 static void _okChildPath(const char* file
, int line
, const char* key
, const char* expected
)
702 result
=getChildString("Arguments", key
);
705 ok_(file
, line
)(FALSE
, "%s expected '%s', but key not found or empty\n", key
, expected
);
708 ok_(file
, line
)(StrCmpPath(result
, expected
) == 0,
709 "%s expected '%s', got '%s'\n", key
, expected
, result
);
712 static void _okChildInt(const char* file
, int line
, const char* key
, int expected
)
715 result
=GetPrivateProfileIntA("Arguments", key
, expected
, child_file
);
716 ok_(file
, line
)(result
== expected
,
717 "%s expected %d, but got %d\n", key
, expected
, result
);
720 #define okChildString(key, expected) _okChildString(__FILE__, __LINE__, (key), (expected))
721 #define okChildPath(key, expected) _okChildPath(__FILE__, __LINE__, (key), (expected))
722 #define okChildInt(key, expected) _okChildInt(__FILE__, __LINE__, (key), (expected))
726 * GetLongPathNameA equivalent that supports Win95 and WinNT
730 static DWORD
get_long_path_name(const char* shortpath
, char* longpath
, DWORD longlen
)
732 char tmplongpath
[MAX_PATH
];
734 DWORD sp
= 0, lp
= 0;
736 WIN32_FIND_DATAA wfd
;
739 if (!shortpath
|| !shortpath
[0])
742 if (shortpath
[1] == ':')
744 tmplongpath
[0] = shortpath
[0];
745 tmplongpath
[1] = ':';
749 while (shortpath
[sp
])
751 /* check for path delimiters and reproduce them */
752 if (shortpath
[sp
] == '\\' || shortpath
[sp
] == '/')
754 if (!lp
|| tmplongpath
[lp
-1] != '\\')
756 /* strip double "\\" */
757 tmplongpath
[lp
++] = '\\';
759 tmplongpath
[lp
] = 0; /* terminate string */
765 if (sp
== 0 && p
[0] == '.' && (p
[1] == '/' || p
[1] == '\\'))
767 tmplongpath
[lp
++] = *p
++;
768 tmplongpath
[lp
++] = *p
++;
770 for (; *p
&& *p
!= '/' && *p
!= '\\'; p
++);
771 tmplen
= p
- (shortpath
+ sp
);
772 lstrcpyn(tmplongpath
+ lp
, shortpath
+ sp
, tmplen
+ 1);
773 /* Check if the file exists and use the existing file name */
774 goit
= FindFirstFileA(tmplongpath
, &wfd
);
775 if (goit
== INVALID_HANDLE_VALUE
)
778 strcpy(tmplongpath
+ lp
, wfd
.cFileName
);
779 lp
+= strlen(tmplongpath
+ lp
);
782 tmplen
= strlen(shortpath
) - 1;
783 if ((shortpath
[tmplen
] == '/' || shortpath
[tmplen
] == '\\') &&
784 (tmplongpath
[lp
- 1] != '/' && tmplongpath
[lp
- 1] != '\\'))
785 tmplongpath
[lp
++] = shortpath
[tmplen
];
788 tmplen
= strlen(tmplongpath
) + 1;
789 if (tmplen
<= longlen
)
791 strcpy(longpath
, tmplongpath
);
792 tmplen
--; /* length without 0 */
800 * PathFindFileNameA equivalent that supports WinNT
804 static LPSTR
path_find_file_name(LPCSTR lpszPath
)
806 LPCSTR lastSlash
= lpszPath
;
808 while (lpszPath
&& *lpszPath
)
810 if ((*lpszPath
== '\\' || *lpszPath
== '/' || *lpszPath
== ':') &&
811 lpszPath
[1] && lpszPath
[1] != '\\' && lpszPath
[1] != '/')
812 lastSlash
= lpszPath
+ 1;
813 lpszPath
= CharNext(lpszPath
);
815 return (LPSTR
)lastSlash
;
824 static const char* testfiles
[]=
826 "%s\\test file.shlexec",
827 "%s\\%%nasty%% $file.shlexec",
828 "%s\\test file.noassoc",
829 "%s\\test file.noassoc.shlexec",
830 "%s\\test file.shlexec.noassoc",
831 "%s\\test_shortcut_shlexec.lnk",
832 "%s\\test_shortcut_exe.lnk",
834 "%s\\test file.shlfoo",
836 "%s\\masked file.shlexec",
841 "%s\\simple.shlexec",
842 "%s\\drawback_file.noassoc",
843 "%s\\drawback_file.noassoc foo.shlexec",
844 "%s\\drawback_nonexist.noassoc foo.shlexec",
851 const char* basename
;
856 static filename_tests_t filename_tests
[]=
858 /* Test bad / nonexistent filenames */
859 {NULL
, "%s\\nonexistent.shlexec", 0x0, SE_ERR_FNF
},
860 {NULL
, "%s\\nonexistent.noassoc", 0x0, SE_ERR_FNF
},
863 {NULL
, "%s\\test file.shlexec", 0x0, 33},
864 {NULL
, "%s\\test file.shlexec.", 0x0, 33},
865 {NULL
, "%s\\%%nasty%% $file.shlexec", 0x0, 33},
866 {NULL
, "%s/test file.shlexec", 0x0, 33},
868 /* Test filenames with no association */
869 {NULL
, "%s\\test file.noassoc", 0x0, SE_ERR_NOASSOC
},
871 /* Test double extensions */
872 {NULL
, "%s\\test file.noassoc.shlexec", 0x0, 33},
873 {NULL
, "%s\\test file.shlexec.noassoc", 0x0, SE_ERR_NOASSOC
},
875 /* Test alternate verbs */
876 {"LowerL", "%s\\nonexistent.shlexec", 0x0, SE_ERR_FNF
},
877 {"LowerL", "%s\\test file.noassoc", 0x0, SE_ERR_NOASSOC
},
879 {"QuotedLowerL", "%s\\test file.shlexec", 0x0, 33},
880 {"QuotedUpperL", "%s\\test file.shlexec", 0x0, 33},
882 /* Test file masked due to space */
883 {NULL
, "%s\\masked file.shlexec", 0x1, 33},
884 /* Test if quoting prevents the masking */
885 {NULL
, "%s\\masked file.shlexec", 0x40, 33},
890 static filename_tests_t noquotes_tests
[]=
892 /* Test unquoted '%1' thingies */
893 {"NoQuotes", "%s\\test file.shlexec", 0xa, 33},
894 {"LowerL", "%s\\test file.shlexec", 0xa, 33},
895 {"UpperL", "%s\\test file.shlexec", 0xa, 33},
900 static void test_lpFile_parsed(void)
902 /* basename tmpdir */
903 const char* shorttmpdir
;
905 const char *testfile
;
906 char fileA
[MAX_PATH
];
910 GetTempPathA(sizeof(fileA
), fileA
);
911 shorttmpdir
= tmpdir
+ strlen(fileA
);
913 /* ensure tmpdir is in %TEMP%: GetTempPath() can succeed even if TEMP is undefined */
914 SetEnvironmentVariableA("TEMP", fileA
);
916 /* existing "drawback_file.noassoc" prevents finding "drawback_file.noassoc foo.shlexec" on wine */
917 testfile
= "%s\\drawback_file.noassoc foo.shlexec";
918 sprintf(fileA
, testfile
, tmpdir
);
919 rc
=shell_execute(NULL
, fileA
, NULL
, NULL
);
922 "expected success (33), got %s (%d), lpFile: %s\n",
923 rc
> 32 ? "success" : "failure", rc
, fileA
927 /* if quoted, existing "drawback_file.noassoc" not prevents finding "drawback_file.noassoc foo.shlexec" on wine */
928 testfile
= "\"%s\\drawback_file.noassoc foo.shlexec\"";
929 sprintf(fileA
, testfile
, tmpdir
);
930 rc
=shell_execute(NULL
, fileA
, NULL
, NULL
);
931 ok(rc
>32 || broken(rc
== 2) /* Win95/NT4 */,
932 "expected success (33), got %s (%d), lpFile: %s\n",
933 rc
> 32 ? "success" : "failure", rc
, fileA
936 /* error should be 2, not 31 */
937 testfile
= "\"%s\\drawback_file.noassoc\" foo.shlexec";
938 sprintf(fileA
, testfile
, tmpdir
);
939 rc
=shell_execute(NULL
, fileA
, NULL
, NULL
);
941 "expected failure (2), got %s (%d), lpFile: %s\n",
942 rc
> 32 ? "success" : "failure", rc
, fileA
945 /* ""command"" not works on wine (and real win9x and w2k) */
946 testfile
= "\"\"%s\\simple.shlexec\"\"";
947 sprintf(fileA
, testfile
, tmpdir
);
948 rc
=shell_execute(NULL
, fileA
, NULL
, NULL
);
950 ok(rc
>32 || broken(rc
== 2) /* Win9x/2000 */,
951 "expected success (33), got %s (%d), lpFile: %s\n",
952 rc
> 32 ? "success" : "failure", rc
, fileA
956 /* nonexisting "drawback_nonexist.noassoc" not prevents finding "drawback_nonexist.noassoc foo.shlexec" on wine */
957 testfile
= "%s\\drawback_nonexist.noassoc foo.shlexec";
958 sprintf(fileA
, testfile
, tmpdir
);
959 rc
=shell_execute(NULL
, fileA
, NULL
, NULL
);
961 "expected success (33), got %s (%d), lpFile: %s\n",
962 rc
> 32 ? "success" : "failure", rc
, fileA
965 /* is SEE_MASK_DOENVSUBST default flag? Should only be when XP emulates 9x (XP bug or real 95 or ME behavior ?) */
966 testfile
= "%%TEMP%%\\%s\\simple.shlexec";
967 sprintf(fileA
, testfile
, shorttmpdir
);
968 rc
=shell_execute(NULL
, fileA
, NULL
, NULL
);
971 "expected failure (2), got %s (%d), lpFile: %s\n",
972 rc
> 32 ? "success" : "failure", rc
, fileA
977 testfile
= "\"%%TEMP%%\\%s\\simple.shlexec\"";
978 sprintf(fileA
, testfile
, shorttmpdir
);
979 rc
=shell_execute(NULL
, fileA
, NULL
, NULL
);
982 "expected failure (2), got %s (%d), lpFile: %s\n",
983 rc
> 32 ? "success" : "failure", rc
, fileA
987 /* test SEE_MASK_DOENVSUBST works */
988 testfile
= "%%TEMP%%\\%s\\simple.shlexec";
989 sprintf(fileA
, testfile
, shorttmpdir
);
990 rc
=shell_execute_ex(SEE_MASK_DOENVSUBST
| SEE_MASK_FLAG_NO_UI
, NULL
, fileA
, NULL
, NULL
);
992 "expected success (33), got %s (%d), lpFile: %s\n",
993 rc
> 32 ? "success" : "failure", rc
, fileA
996 /* quoted lpFile not works only on real win95 and nt4 */
997 testfile
= "\"%%TEMP%%\\%s\\simple.shlexec\"";
998 sprintf(fileA
, testfile
, shorttmpdir
);
999 rc
=shell_execute_ex(SEE_MASK_DOENVSUBST
| SEE_MASK_FLAG_NO_UI
, NULL
, fileA
, NULL
, NULL
);
1000 ok(rc
>32 || broken(rc
== 2) /* Win95/NT4 */,
1001 "expected success (33), got %s (%d), lpFile: %s\n",
1002 rc
> 32 ? "success" : "failure", rc
, fileA
1007 static void test_argify(void)
1009 char fileA
[MAX_PATH
];
1013 sprintf(fileA
, "%s\\test file.shlexec", tmpdir
);
1016 rc
=shell_execute("NoQuotesParam2", fileA
, "a b", NULL
);
1018 "expected success (33), got %s (%d), lpFile: %s\n",
1019 rc
> 32 ? "success" : "failure", rc
, fileA
1023 okChildInt("argcA", 5);
1024 okChildString("argvA4", "a");
1028 /* '"a"""' -> 'a"' */
1029 rc
=shell_execute("NoQuotesParam2", fileA
, "\"a:\"\"some string\"\"\"", NULL
);
1031 "expected success (33), got %s (%d), lpFile: %s\n",
1032 rc
> 32 ? "success" : "failure", rc
, fileA
1036 okChildInt("argcA", 5);
1038 okChildString("argvA4", "a:some string");
1043 /* backslash isn't escape char
1044 * '"a\""' -> '"a\""' */
1045 rc
=shell_execute("NoQuotesParam2", fileA
, "\"a:\\\"some string\\\"\"", NULL
);
1047 "expected success (33), got %s (%d), lpFile: %s\n",
1048 rc
> 32 ? "success" : "failure", rc
, fileA
1052 okChildInt("argcA", 5);
1054 okChildString("argvA4", "a:\\");
1059 /* \t isn't whitespace */
1060 rc
=shell_execute("QuotedParam2", fileA
, "a\tb c", NULL
);
1062 "expected success (33), got %s (%d), lpFile: %s\n",
1063 rc
> 32 ? "success" : "failure", rc
, fileA
1067 okChildInt("argcA", 5);
1069 okChildString("argvA4", "a\tb");
1074 rc
=shell_execute("NoQuotesAllParams", fileA
, "a b c d e f g h", NULL
);
1076 "expected success (33), got %s (%d), lpFile: %s\n",
1077 rc
> 32 ? "success" : "failure", rc
, fileA
1082 okChildInt("argcA", 12);
1083 okChildString("argvA4", "a");
1084 okChildString("argvA11", "h");
1088 /* %* can sometimes contain only whitespaces and no args */
1089 rc
=shell_execute("QuotedAllParams", fileA
, " ", NULL
);
1091 "expected success (33), got %s (%d), lpFile: %s\n",
1092 rc
> 32 ? "success" : "failure", rc
, fileA
1097 okChildInt("argcA", 5);
1098 okChildString("argvA4", " ");
1103 rc
=shell_execute("NoQuotesParams345etc", fileA
, "a b c d e f g h", NULL
);
1105 "expected success (33), got %s (%d), lpFile: %s\n",
1106 rc
> 32 ? "success" : "failure", rc
, fileA
1111 okChildInt("argcA", 11);
1112 okChildString("argvA4", "b");
1113 okChildString("argvA10", "h");
1117 /* %~3 is rest of command line starting with whitespaces after 2nd arg */
1118 rc
=shell_execute("QuotedParams345etc", fileA
, "a ", NULL
);
1120 "expected success (33), got %s (%d), lpFile: %s\n",
1121 rc
> 32 ? "success" : "failure", rc
, fileA
1125 okChildInt("argcA", 5);
1127 okChildString("argvA4", " ");
1133 static void test_filename(void)
1135 char filename
[MAX_PATH
];
1136 const filename_tests_t
* test
;
1140 test
=filename_tests
;
1141 while (test
->basename
)
1143 BOOL quotedfile
= FALSE
;
1145 if (skip_noassoc_tests
&& test
->rc
== SE_ERR_NOASSOC
)
1147 win_skip("Skipping shellexecute of file with unassociated extension\n");
1152 sprintf(filename
, test
->basename
, tmpdir
);
1153 if (strchr(filename
, '/'))
1163 if ((test
->todo
& 0x40)==0)
1165 rc
=shell_execute(test
->verb
, filename
, NULL
, NULL
);
1169 char quoted
[MAX_PATH
+ 2];
1172 sprintf(quoted
, "\"%s\"", filename
);
1173 rc
=shell_execute(test
->verb
, quoted
, NULL
, NULL
);
1177 if ((test
->todo
& 0x1)==0)
1180 broken(quotedfile
&& rc
== 2), /* NT4 */
1181 "%s failed: rc=%d err=%d\n", shell_call
,
1182 rc
, GetLastError());
1186 ok(rc
==test
->rc
, "%s failed: rc=%d err=%d\n", shell_call
,
1187 rc
, GetLastError());
1192 if ((test
->todo
& 0x2)==0)
1194 okChildInt("argcA", 5);
1198 okChildInt("argcA", 5);
1200 verb
=(test
->verb
? test
->verb
: "Open");
1201 if ((test
->todo
& 0x4)==0)
1203 okChildString("argvA3", verb
);
1207 okChildString("argvA3", verb
);
1209 if ((test
->todo
& 0x8)==0)
1211 okChildPath("argvA4", filename
);
1215 okChildPath("argvA4", filename
);
1221 test
=noquotes_tests
;
1222 while (test
->basename
)
1224 sprintf(filename
, test
->basename
, tmpdir
);
1225 rc
=shell_execute(test
->verb
, filename
, NULL
, NULL
);
1228 if ((test
->todo
& 0x1)==0)
1230 ok(rc
==test
->rc
, "%s failed: rc=%d err=%d\n", shell_call
,
1231 rc
, GetLastError());
1235 ok(rc
==test
->rc
, "%s failed: rc=%d err=%d\n", shell_call
,
1236 rc
, GetLastError());
1244 verb
=(test
->verb
? test
->verb
: "Open");
1245 if ((test
->todo
& 0x4)==0)
1247 okChildString("argvA3", verb
);
1251 okChildString("argvA3", verb
);
1260 space
=strchr(str
, ' ');
1263 sprintf(attrib
, "argvA%d", count
);
1264 if ((test
->todo
& 0x8)==0)
1266 okChildPath(attrib
, str
);
1270 okChildPath(attrib
, str
);
1277 if ((test
->todo
& 0x2)==0)
1279 okChildInt("argcA", count
);
1283 okChildInt("argcA", count
);
1289 if (dllver
.dwMajorVersion
!= 0)
1291 /* The more recent versions of shell32.dll accept quoted filenames
1292 * while older ones (e.g. 4.00) don't. Still we want to test this
1293 * because IE 6 depends on the new behavior.
1294 * One day we may need to check the exact version of the dll but for
1295 * now making sure DllGetVersion() is present is sufficient.
1297 sprintf(filename
, "\"%s\\test file.shlexec\"", tmpdir
);
1298 rc
=shell_execute(NULL
, filename
, NULL
, NULL
);
1299 ok(rc
> 32, "%s failed: rc=%d err=%d\n", shell_call
, rc
,
1301 okChildInt("argcA", 5);
1302 okChildString("argvA3", "Open");
1303 sprintf(filename
, "%s\\test file.shlexec", tmpdir
);
1304 okChildPath("argvA4", filename
);
1308 static void test_find_executable(void)
1310 char filename
[MAX_PATH
];
1311 char command
[MAX_PATH
];
1312 const filename_tests_t
* test
;
1315 if (!create_test_association(".sfe"))
1317 skip("Unable to create association for '.sfe'\n");
1320 create_test_verb(".sfe", "Open", 1, "%1");
1322 /* Don't test FindExecutable(..., NULL), it always crashes */
1324 strcpy(command
, "your word");
1325 if (0) /* Can crash on Vista! */
1327 rc
=(INT_PTR
)FindExecutableA(NULL
, NULL
, command
);
1328 ok(rc
== SE_ERR_FNF
|| rc
> 32 /* nt4 */, "FindExecutable(NULL) returned %ld\n", rc
);
1329 ok(strcmp(command
, "your word") != 0, "FindExecutable(NULL) returned command=[%s]\n", command
);
1332 strcpy(command
, "your word");
1333 rc
=(INT_PTR
)FindExecutableA(tmpdir
, NULL
, command
);
1334 ok(rc
== SE_ERR_NOASSOC
/* >= win2000 */ || rc
> 32 /* win98, nt4 */, "FindExecutable(NULL) returned %ld\n", rc
);
1335 ok(strcmp(command
, "your word") != 0, "FindExecutable(NULL) returned command=[%s]\n", command
);
1337 sprintf(filename
, "%s\\test file.sfe", tmpdir
);
1338 rc
=(INT_PTR
)FindExecutableA(filename
, NULL
, command
);
1339 ok(rc
> 32, "FindExecutable(%s) returned %ld\n", filename
, rc
);
1340 /* Depending on the platform, command could be '%1' or 'test file.sfe' */
1342 rc
=(INT_PTR
)FindExecutableA("test file.sfe", tmpdir
, command
);
1343 ok(rc
> 32, "FindExecutable(%s) returned %ld\n", filename
, rc
);
1345 rc
=(INT_PTR
)FindExecutableA("test file.sfe", NULL
, command
);
1346 ok(rc
== SE_ERR_FNF
, "FindExecutable(%s) returned %ld\n", filename
, rc
);
1348 delete_test_association(".sfe");
1350 if (!create_test_association(".shl"))
1352 skip("Unable to create association for '.shl'\n");
1355 create_test_verb(".shl", "Open", 0, "Open");
1357 sprintf(filename
, "%s\\test file.shl", tmpdir
);
1358 rc
=(INT_PTR
)FindExecutableA(filename
, NULL
, command
);
1359 ok(rc
== SE_ERR_FNF
/* NT4 */ || rc
> 32, "FindExecutable(%s) returned %ld\n", filename
, rc
);
1361 sprintf(filename
, "%s\\test file.shlfoo", tmpdir
);
1362 rc
=(INT_PTR
)FindExecutableA(filename
, NULL
, command
);
1364 delete_test_association(".shl");
1368 /* On Windows XP and 2003 FindExecutable() is completely broken.
1369 * Probably what it does is convert the filename to 8.3 format,
1370 * which as a side effect converts the '.shlfoo' extension to '.shl',
1371 * and then tries to find an association for '.shl'. This means it
1372 * will normally fail on most extensions with more than 3 characters,
1373 * like '.mpeg', etc.
1374 * Also it means we cannot do any other test.
1376 win_skip("FindExecutable() is broken -> not running 4+ character extension tests\n");
1380 test
=filename_tests
;
1381 while (test
->basename
)
1383 sprintf(filename
, test
->basename
, tmpdir
);
1384 if (strchr(filename
, '/'))
1395 /* Win98 does not '\0'-terminate command! */
1396 memset(command
, '\0', sizeof(command
));
1397 rc
=(INT_PTR
)FindExecutableA(filename
, NULL
, command
);
1400 if ((test
->todo
& 0x10)==0)
1402 ok(rc
==test
->rc
, "FindExecutable(%s) failed: rc=%ld\n", filename
, rc
);
1406 ok(rc
==test
->rc
, "FindExecutable(%s) failed: rc=%ld\n", filename
, rc
);
1411 equal
=strcmp(command
, argv0
) == 0 ||
1412 /* NT4 returns an extra 0x8 character! */
1413 (strlen(command
) == strlen(argv0
)+1 && strncmp(command
, argv0
, strlen(argv0
)) == 0);
1414 if ((test
->todo
& 0x20)==0)
1416 ok(equal
, "FindExecutable(%s) returned command='%s' instead of '%s'\n",
1417 filename
, command
, argv0
);
1421 ok(equal
, "FindExecutable(%s) returned command='%s' instead of '%s'\n",
1422 filename
, command
, argv0
);
1430 static filename_tests_t lnk_tests
[]=
1432 /* Pass bad / nonexistent filenames as a parameter */
1433 {NULL
, "%s\\nonexistent.shlexec", 0xa, 33},
1434 {NULL
, "%s\\nonexistent.noassoc", 0xa, 33},
1436 /* Pass regular paths as a parameter */
1437 {NULL
, "%s\\test file.shlexec", 0xa, 33},
1438 {NULL
, "%s/%%nasty%% $file.shlexec", 0xa, 33},
1440 /* Pass filenames with no association as a parameter */
1441 {NULL
, "%s\\test file.noassoc", 0xa, 33},
1446 static void test_lnks(void)
1448 char filename
[MAX_PATH
];
1449 char params
[MAX_PATH
];
1450 const filename_tests_t
* test
;
1453 sprintf(filename
, "%s\\test_shortcut_shlexec.lnk", tmpdir
);
1454 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, filename
, NULL
, NULL
);
1455 ok(rc
> 32, "%s failed: rc=%d err=%d\n", shell_call
, rc
,
1457 okChildInt("argcA", 5);
1458 okChildString("argvA3", "Open");
1459 sprintf(params
, "%s\\test file.shlexec", tmpdir
);
1460 get_long_path_name(params
, filename
, sizeof(filename
));
1461 okChildPath("argvA4", filename
);
1463 sprintf(filename
, "%s\\test_shortcut_exe.lnk", tmpdir
);
1464 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, filename
, NULL
, NULL
);
1465 ok(rc
> 32, "%s failed: rc=%d err=%d\n", shell_call
, rc
,
1467 okChildInt("argcA", 4);
1468 okChildString("argvA3", "Lnk");
1470 if (dllver
.dwMajorVersion
>=6)
1473 /* Recent versions of shell32.dll accept '/'s in shortcut paths.
1474 * Older versions don't or are quite buggy in this regard.
1476 sprintf(filename
, "%s\\test_shortcut_exe.lnk", tmpdir
);
1484 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, filename
, NULL
, NULL
);
1485 ok(rc
> 32, "%s failed: rc=%d err=%d\n", shell_call
, rc
,
1487 okChildInt("argcA", 4);
1488 okChildString("argvA3", "Lnk");
1491 sprintf(filename
, "%s\\test_shortcut_exe.lnk", tmpdir
);
1493 while (test
->basename
)
1496 sprintf(params
+1, test
->basename
, tmpdir
);
1497 strcat(params
,"\"");
1498 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, filename
, params
,
1502 if ((test
->todo
& 0x1)==0)
1504 ok(rc
==test
->rc
, "%s failed: rc=%d err=%d\n", shell_call
,
1505 rc
, GetLastError());
1509 ok(rc
==test
->rc
, "%s failed: rc=%d err=%d\n", shell_call
,
1510 rc
, GetLastError());
1514 if ((test
->todo
& 0x2)==0)
1516 okChildInt("argcA", 5);
1520 okChildInt("argcA", 5);
1522 if ((test
->todo
& 0x4)==0)
1524 okChildString("argvA3", "Lnk");
1528 okChildString("argvA3", "Lnk");
1530 sprintf(params
, test
->basename
, tmpdir
);
1531 if ((test
->todo
& 0x8)==0)
1533 okChildPath("argvA4", params
);
1537 okChildPath("argvA4", params
);
1545 static void test_exes(void)
1547 char filename
[MAX_PATH
];
1551 sprintf(params
, "shlexec \"%s\" Exec", child_file
);
1553 /* We need NOZONECHECKS on Win2003 to block a dialog */
1554 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, argv0
, params
,
1556 ok(rc
> 32, "%s returned %d\n", shell_call
, rc
);
1557 okChildInt("argcA", 4);
1558 okChildString("argvA3", "Exec");
1560 if (! skip_noassoc_tests
)
1562 sprintf(filename
, "%s\\test file.noassoc", tmpdir
);
1563 if (CopyFile(argv0
, filename
, FALSE
))
1565 rc
=shell_execute(NULL
, filename
, params
, NULL
);
1567 ok(rc
==SE_ERR_NOASSOC
, "%s succeeded: rc=%d\n", shell_call
, rc
);
1573 win_skip("Skipping shellexecute of file with unassociated extension\n");
1577 static void test_exes_long(void)
1579 char filename
[MAX_PATH
];
1581 char longparam
[MAX_PATH
];
1584 for (rc
= 0; rc
< MAX_PATH
; rc
++)
1585 longparam
[rc
]='a'+rc
%26;
1586 longparam
[MAX_PATH
-1]=0;
1589 sprintf(params
, "shlexec \"%s\" %s", child_file
,longparam
);
1591 /* We need NOZONECHECKS on Win2003 to block a dialog */
1592 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, argv0
, params
,
1594 ok(rc
> 32, "%s returned %d\n", shell_call
, rc
);
1595 okChildInt("argcA", 4);
1596 okChildString("argvA3", longparam
);
1598 if (! skip_noassoc_tests
)
1600 sprintf(filename
, "%s\\test file.noassoc", tmpdir
);
1601 if (CopyFile(argv0
, filename
, FALSE
))
1603 rc
=shell_execute(NULL
, filename
, params
, NULL
);
1605 ok(rc
==SE_ERR_NOASSOC
, "%s succeeded: rc=%d\n", shell_call
, rc
);
1611 win_skip("Skipping shellexecute of file with unassociated extension\n");
1617 const char* command
;
1618 const char* ddeexec
;
1619 const char* application
;
1623 const char* expectedDdeExec
;
1627 static dde_tests_t dde_tests
[] =
1629 /* Test passing and not passing command-line
1630 * argument, no DDE */
1631 {"", NULL
, NULL
, NULL
, NULL
, FALSE
, "", 0x0},
1632 {"\"%1\"", NULL
, NULL
, NULL
, NULL
, TRUE
, "", 0x0},
1634 /* Test passing and not passing command-line
1635 * argument, with DDE */
1636 {"", "[open(\"%1\")]", "shlexec", "dde", NULL
, FALSE
, "[open(\"%s\")]", 0x0},
1637 {"\"%1\"", "[open(\"%1\")]", "shlexec", "dde", NULL
, TRUE
, "[open(\"%s\")]", 0x0},
1639 /* Test unquoted %1 in command and ddeexec
1640 * (test filename has space) */
1641 {"%1", "[open(%1)]", "shlexec", "dde", NULL
, 2, "[open(%s)]", 0x0},
1643 /* Test ifexec precedence over ddeexec */
1644 {"", "[open(\"%1\")]", "shlexec", "dde", "[ifexec(\"%1\")]", FALSE
, "[ifexec(\"%s\")]", 0x0},
1646 /* Test default DDE topic */
1647 {"", "[open(\"%1\")]", "shlexec", NULL
, NULL
, FALSE
, "[open(\"%s\")]", 0x0},
1649 /* Test default DDE application */
1650 {"", "[open(\"%1\")]", NULL
, "dde", NULL
, FALSE
, "[open(\"%s\")]", 0x0},
1652 {NULL
, NULL
, NULL
, NULL
, NULL
, 0, 0x0}
1655 static DWORD WINAPI
hooked_WaitForInputIdle(HANDLE process
, DWORD timeout
)
1657 return WaitForSingleObject(dde_ready_event
, timeout
);
1661 * WaitForInputIdle() will normally return immediately for console apps. That's
1662 * a problem for us because ShellExecute will assume that an app is ready to
1663 * receive DDE messages after it has called WaitForInputIdle() on that app.
1664 * To work around that we install our own version of WaitForInputIdle() that
1665 * will wait for the child to explicitly tell us that it is ready. We do that
1666 * by changing the entry for WaitForInputIdle() in the shell32 import address
1669 static void hook_WaitForInputIdle(void *new_func
)
1672 PIMAGE_NT_HEADERS nt_headers
;
1673 DWORD import_directory_rva
;
1674 PIMAGE_IMPORT_DESCRIPTOR import_descriptor
;
1676 base
= (char *) GetModuleHandleA("shell32.dll");
1677 nt_headers
= (PIMAGE_NT_HEADERS
)(base
+ ((PIMAGE_DOS_HEADER
) base
)->e_lfanew
);
1678 import_directory_rva
= nt_headers
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
;
1680 /* Search for the correct imported module by walking the import descriptors */
1681 import_descriptor
= (PIMAGE_IMPORT_DESCRIPTOR
)(base
+ import_directory_rva
);
1682 while (U(*import_descriptor
).OriginalFirstThunk
!= 0)
1684 char *import_module_name
;
1686 import_module_name
= base
+ import_descriptor
->Name
;
1687 if (lstrcmpiA(import_module_name
, "user32.dll") == 0 ||
1688 lstrcmpiA(import_module_name
, "user32") == 0)
1690 PIMAGE_THUNK_DATA int_entry
;
1691 PIMAGE_THUNK_DATA iat_entry
;
1693 /* The import name table and import address table are two parallel
1694 * arrays. We need the import name table to find the imported
1695 * routine and the import address table to patch the address, so
1696 * walk them side by side */
1697 int_entry
= (PIMAGE_THUNK_DATA
)(base
+ U(*import_descriptor
).OriginalFirstThunk
);
1698 iat_entry
= (PIMAGE_THUNK_DATA
)(base
+ import_descriptor
->FirstThunk
);
1699 while (int_entry
->u1
.Ordinal
!= 0)
1701 if (! IMAGE_SNAP_BY_ORDINAL(int_entry
->u1
.Ordinal
))
1703 PIMAGE_IMPORT_BY_NAME import_by_name
;
1704 import_by_name
= (PIMAGE_IMPORT_BY_NAME
)(base
+ int_entry
->u1
.AddressOfData
);
1705 if (lstrcmpA((char *) import_by_name
->Name
, "WaitForInputIdle") == 0)
1707 /* Found the correct routine in the correct imported module. Patch it. */
1709 VirtualProtect(&iat_entry
->u1
.Function
, sizeof(ULONG_PTR
), PAGE_READWRITE
, &old_prot
);
1710 iat_entry
->u1
.Function
= (ULONG_PTR
) new_func
;
1711 VirtualProtect(&iat_entry
->u1
.Function
, sizeof(ULONG_PTR
), old_prot
, &old_prot
);
1721 import_descriptor
++;
1725 static void test_dde(void)
1727 char filename
[MAX_PATH
], defApplication
[MAX_PATH
];
1728 const dde_tests_t
* test
;
1734 hook_WaitForInputIdle((void *) hooked_WaitForInputIdle
);
1736 sprintf(filename
, "%s\\test file.sde", tmpdir
);
1738 /* Default service is application name minus path and extension */
1739 strcpy(defApplication
, strrchr(argv0
, '\\')+1);
1740 *strchr(defApplication
, '.') = 0;
1742 map
= CreateFileMappingA(INVALID_HANDLE_VALUE
, NULL
, PAGE_READWRITE
, 0,
1743 4096, "winetest_shlexec_dde_map");
1744 shared_block
= MapViewOfFile(map
, FILE_MAP_READ
| FILE_MAP_WRITE
, 0, 0, 4096);
1747 while (test
->command
)
1749 if (!create_test_association(".sde"))
1751 skip("Unable to create association for '.sde'\n");
1754 create_test_verb_dde(".sde", "Open", 0, test
->command
, test
->ddeexec
,
1755 test
->application
, test
->topic
, test
->ifexec
);
1757 if (test
->application
!= NULL
|| test
->topic
!= NULL
)
1759 strcpy(shared_block
, test
->application
? test
->application
: defApplication
);
1760 strcpy(shared_block
+ strlen(shared_block
) + 1, test
->topic
? test
->topic
: SZDDESYS_TOPIC
);
1764 shared_block
[0] = '\0';
1765 shared_block
[1] = '\0';
1769 dde_ready_event
= CreateEventA(NULL
, FALSE
, FALSE
, "winetest_shlexec_dde_ready");
1770 rc
= shell_execute_ex(SEE_MASK_FLAG_DDEWAIT
| SEE_MASK_FLAG_NO_UI
, NULL
, filename
, NULL
, NULL
);
1771 CloseHandle(dde_ready_event
);
1772 if ((test
->todo
& 0x1)==0)
1774 ok(32 < rc
, "%s failed: rc=%d err=%d\n", shell_call
,
1775 rc
, GetLastError());
1779 ok(32 < rc
, "%s failed: rc=%d err=%d\n", shell_call
,
1780 rc
, GetLastError());
1784 if ((test
->todo
& 0x2)==0)
1786 okChildInt("argcA", test
->expectedArgs
+ 3);
1790 okChildInt("argcA", test
->expectedArgs
+ 3);
1792 if (test
->expectedArgs
== 1)
1794 if ((test
->todo
& 0x4) == 0)
1796 okChildPath("argvA3", filename
);
1800 okChildPath("argvA3", filename
);
1803 if ((test
->todo
& 0x8) == 0)
1805 sprintf(params
, test
->expectedDdeExec
, filename
);
1806 okChildPath("ddeExec", params
);
1810 sprintf(params
, test
->expectedDdeExec
, filename
);
1811 okChildPath("ddeExec", params
);
1815 delete_test_association(".sde");
1819 UnmapViewOfFile(shared_block
);
1821 hook_WaitForInputIdle((void *) WaitForInputIdle
);
1824 #define DDE_DEFAULT_APP_VARIANTS 2
1827 const char* command
;
1828 const char* expectedDdeApplication
[DDE_DEFAULT_APP_VARIANTS
];
1830 int rc
[DDE_DEFAULT_APP_VARIANTS
];
1831 } dde_default_app_tests_t
;
1833 static dde_default_app_tests_t dde_default_app_tests
[] =
1835 /* Windows XP and 98 handle default DDE app names in different ways.
1836 * The application name we see in the first test determines the pattern
1837 * of application names and return codes we will look for. */
1839 /* Test unquoted existing filename with a space */
1840 {"%s\\test file.exe", {"test file", "test"}, 0x0, {33, 33}},
1841 {"%s\\test file.exe param", {"test file", "test"}, 0x0, {33, 33}},
1843 /* Test quoted existing filename with a space */
1844 {"\"%s\\test file.exe\"", {"test file", "test file"}, 0x0, {33, 33}},
1845 {"\"%s\\test file.exe\" param", {"test file", "test file"}, 0x0, {33, 33}},
1847 /* Test unquoted filename with a space that doesn't exist, but
1849 {"%s\\test2 file.exe", {"test2", "test2"}, 0x0, {33, 33}},
1850 {"%s\\test2 file.exe param", {"test2", "test2"}, 0x0, {33, 33}},
1852 /* Test quoted filename with a space that does not exist */
1853 {"\"%s\\test2 file.exe\"", {"", "test2 file"}, 0x0, {5, 33}},
1854 {"\"%s\\test2 file.exe\" param", {"", "test2 file"}, 0x0, {5, 33}},
1856 /* Test filename supplied without the extension */
1857 {"%s\\test2", {"test2", "test2"}, 0x0, {33, 33}},
1858 {"%s\\test2 param", {"test2", "test2"}, 0x0, {33, 33}},
1860 /* Test an unquoted nonexistent filename */
1861 {"%s\\notexist.exe", {"", "notexist"}, 0x0, {5, 33}},
1862 {"%s\\notexist.exe param", {"", "notexist"}, 0x0, {5, 33}},
1864 /* Test an application that will be found on the path */
1865 {"cmd", {"cmd", "cmd"}, 0x0, {33, 33}},
1866 {"cmd param", {"cmd", "cmd"}, 0x0, {33, 33}},
1868 /* Test an application that will not be found on the path */
1869 {"xyzwxyzwxyz", {"", "xyzwxyzwxyz"}, 0x0, {5, 33}},
1870 {"xyzwxyzwxyz param", {"", "xyzwxyzwxyz"}, 0x0, {5, 33}},
1872 {NULL
, {NULL
}, 0, {0}}
1878 DWORD threadIdParent
;
1879 } dde_thread_info_t
;
1881 static DWORD CALLBACK
ddeThread(LPVOID arg
)
1883 dde_thread_info_t
*info
= arg
;
1884 assert(info
&& info
->filename
);
1885 PostThreadMessage(info
->threadIdParent
,
1887 shell_execute_ex(SEE_MASK_FLAG_DDEWAIT
| SEE_MASK_FLAG_NO_UI
, NULL
, info
->filename
, NULL
, NULL
),
1892 static void test_dde_default_app(void)
1894 char filename
[MAX_PATH
];
1896 dde_thread_info_t info
= { filename
, GetCurrentThreadId() };
1897 const dde_default_app_tests_t
* test
;
1903 post_quit_on_execute
= FALSE
;
1905 rc
= DdeInitializeA(&ddeInst
, ddeCb
, CBF_SKIP_ALLNOTIFICATIONS
| CBF_FAIL_ADVISES
|
1906 CBF_FAIL_POKES
| CBF_FAIL_REQUESTS
, 0L);
1907 assert(rc
== DMLERR_NO_ERROR
);
1909 sprintf(filename
, "%s\\test file.sde", tmpdir
);
1911 /* It is strictly not necessary to register an application name here, but wine's
1912 * DdeNameService implementation complains if 0L is passed instead of
1913 * hszApplication with DNS_FILTEROFF */
1914 hszApplication
= DdeCreateStringHandleA(ddeInst
, "shlexec", CP_WINANSI
);
1915 hszTopic
= DdeCreateStringHandleA(ddeInst
, "shlexec", CP_WINANSI
);
1916 assert(hszApplication
&& hszTopic
);
1917 assert(DdeNameService(ddeInst
, hszApplication
, 0L, DNS_REGISTER
| DNS_FILTEROFF
));
1919 test
= dde_default_app_tests
;
1920 while (test
->command
)
1922 if (!create_test_association(".sde"))
1924 skip("Unable to create association for '.sde'\n");
1927 sprintf(params
, test
->command
, tmpdir
);
1928 create_test_verb_dde(".sde", "Open", 1, params
, "[test]", NULL
,
1930 ddeApplication
[0] = 0;
1932 /* No application will be run as we will respond to the first DDE event,
1933 * so don't wait for it */
1936 assert(CreateThread(NULL
, 0, ddeThread
, &info
, 0, &threadId
));
1937 while (GetMessage(&msg
, NULL
, 0, 0)) DispatchMessage(&msg
);
1938 rc
= msg
.wParam
> 32 ? 33 : msg
.wParam
;
1940 /* First test, find which set of test data we expect to see */
1941 if (test
== dde_default_app_tests
)
1944 for (i
=0; i
<DDE_DEFAULT_APP_VARIANTS
; i
++)
1946 if (!strcmp(ddeApplication
, test
->expectedDdeApplication
[i
]))
1952 if (i
== DDE_DEFAULT_APP_VARIANTS
)
1953 skip("Default DDE application test does not match any available results, using first expected data set.\n");
1956 if ((test
->todo
& 0x1)==0)
1958 ok(rc
==test
->rc
[which
], "%s failed: rc=%d err=%d\n", shell_call
,
1959 rc
, GetLastError());
1963 ok(rc
==test
->rc
[which
], "%s failed: rc=%d err=%d\n", shell_call
,
1964 rc
, GetLastError());
1968 if ((test
->todo
& 0x2)==0)
1970 ok(!strcmp(ddeApplication
, test
->expectedDdeApplication
[which
]),
1971 "Expected application '%s', got '%s'\n",
1972 test
->expectedDdeApplication
[which
], ddeApplication
);
1976 ok(!strcmp(ddeApplication
, test
->expectedDdeApplication
[which
]),
1977 "Expected application '%s', got '%s'\n",
1978 test
->expectedDdeApplication
[which
], ddeApplication
);
1982 delete_test_association(".sde");
1986 assert(DdeNameService(ddeInst
, hszApplication
, 0L, DNS_UNREGISTER
));
1987 assert(DdeFreeStringHandle(ddeInst
, hszTopic
));
1988 assert(DdeFreeStringHandle(ddeInst
, hszApplication
));
1989 assert(DdeUninitialize(ddeInst
));
1992 static void init_test(void)
1995 HRESULT (WINAPI
*pDllGetVersion
)(DLLVERSIONINFO
*);
1996 char filename
[MAX_PATH
];
1997 WCHAR lnkfile
[MAX_PATH
];
1999 const char* const * testfile
;
2004 hdll
=GetModuleHandleA("shell32.dll");
2005 pDllGetVersion
=(void*)GetProcAddress(hdll
, "DllGetVersion");
2008 dllver
.cbSize
=sizeof(dllver
);
2009 pDllGetVersion(&dllver
);
2010 trace("major=%d minor=%d build=%d platform=%d\n",
2011 dllver
.dwMajorVersion
, dllver
.dwMinorVersion
,
2012 dllver
.dwBuildNumber
, dllver
.dwPlatformID
);
2016 memset(&dllver
, 0, sizeof(dllver
));
2019 r
= CoInitialize(NULL
);
2020 ok(r
== S_OK
, "CoInitialize failed (0x%08x)\n", r
);
2024 rc
=GetModuleFileName(NULL
, argv0
, sizeof(argv0
));
2025 assert(rc
!=0 && rc
<sizeof(argv0
));
2026 if (GetFileAttributes(argv0
)==INVALID_FILE_ATTRIBUTES
)
2028 strcat(argv0
, ".so");
2029 ok(GetFileAttributes(argv0
)!=INVALID_FILE_ATTRIBUTES
,
2030 "unable to find argv0!\n");
2033 GetTempPathA(sizeof(filename
), filename
);
2034 GetTempFileNameA(filename
, "wt", 0, tmpdir
);
2035 DeleteFileA( tmpdir
);
2036 rc
= CreateDirectoryA( tmpdir
, NULL
);
2037 ok( rc
, "failed to create %s err %u\n", tmpdir
, GetLastError() );
2038 rc
= GetTempFileNameA(tmpdir
, "wt", 0, child_file
);
2040 init_event(child_file
);
2042 /* Set up the test files */
2048 sprintf(filename
, *testfile
, tmpdir
);
2049 hfile
=CreateFile(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
2050 FILE_ATTRIBUTE_NORMAL
, NULL
);
2051 if (hfile
==INVALID_HANDLE_VALUE
)
2053 trace("unable to create '%s': err=%d\n", filename
, GetLastError());
2060 /* Setup the test shortcuts */
2061 sprintf(filename
, "%s\\test_shortcut_shlexec.lnk", tmpdir
);
2062 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, lnkfile
, sizeof(lnkfile
)/sizeof(*lnkfile
));
2063 desc
.description
=NULL
;
2065 sprintf(filename
, "%s\\test file.shlexec", tmpdir
);
2068 desc
.arguments
="ignored";
2073 create_lnk(lnkfile
, &desc
, 0);
2075 sprintf(filename
, "%s\\test_shortcut_exe.lnk", tmpdir
);
2076 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, lnkfile
, sizeof(lnkfile
)/sizeof(*lnkfile
));
2077 desc
.description
=NULL
;
2081 sprintf(params
, "shlexec \"%s\" Lnk", child_file
);
2082 desc
.arguments
=params
;
2087 create_lnk(lnkfile
, &desc
, 0);
2089 /* Create a basic association suitable for most tests */
2090 if (!create_test_association(".shlexec"))
2092 skip("Unable to create association for '.shlexec'\n");
2095 create_test_verb(".shlexec", "Open", 0, "Open \"%1\"");
2096 create_test_verb(".shlexec", "NoQuotes", 0, "NoQuotes %1");
2097 create_test_verb(".shlexec", "LowerL", 0, "LowerL %l");
2098 create_test_verb(".shlexec", "QuotedLowerL", 0, "QuotedLowerL \"%l\"");
2099 create_test_verb(".shlexec", "UpperL", 0, "UpperL %L");
2100 create_test_verb(".shlexec", "QuotedUpperL", 0, "QuotedUpperL \"%L\"");
2102 create_test_verb(".shlexec", "NoQuotesParam2", 0, "NoQuotesParam2 %2");
2103 create_test_verb(".shlexec", "QuotedParam2", 0, "QuotedParam2 \"%2\"");
2105 create_test_verb(".shlexec", "NoQuotesAllParams", 0, "NoQuotesAllParams %*");
2106 create_test_verb(".shlexec", "QuotedAllParams", 0, "QuotedAllParams \"%*\"");
2108 create_test_verb(".shlexec", "NoQuotesParams345etc", 0, "NoQuotesParams345etc %~3");
2109 create_test_verb(".shlexec", "QuotedParams345etc", 0, "QuotedParams345etc \"%~3\"");
2112 static void cleanup_test(void)
2114 char filename
[MAX_PATH
];
2115 const char* const * testfile
;
2117 /* Delete the test files */
2121 sprintf(filename
, *testfile
, tmpdir
);
2122 /* Make sure we can delete the files ('test file.noassoc' is read-only now) */
2123 SetFileAttributes(filename
, FILE_ATTRIBUTE_NORMAL
);
2124 DeleteFile(filename
);
2127 DeleteFile(child_file
);
2128 RemoveDirectoryA(tmpdir
);
2130 /* Delete the test association */
2131 delete_test_association(".shlexec");
2133 CloseHandle(hEvent
);
2138 static void test_commandline(void)
2140 static const WCHAR one
[] = {'o','n','e',0};
2141 static const WCHAR two
[] = {'t','w','o',0};
2142 static const WCHAR three
[] = {'t','h','r','e','e',0};
2143 static const WCHAR four
[] = {'f','o','u','r',0};
2145 static const WCHAR fmt1
[] = {'%','s',' ','%','s',' ','%','s',' ','%','s',0};
2146 static const WCHAR fmt2
[] = {' ','%','s',' ','%','s',' ','%','s',' ','%','s',0};
2147 static const WCHAR fmt3
[] = {'%','s','=','%','s',' ','%','s','=','\"','%','s','\"',0};
2148 static const WCHAR fmt4
[] = {'\"','%','s','\"',' ','\"','%','s',' ','%','s','\"',' ','%','s',0};
2149 static const WCHAR fmt5
[] = {'\\','\"','%','s','\"',' ','%','s','=','\"','%','s','\\','\"',' ','\"','%','s','\\','\"',0};
2150 static const WCHAR fmt6
[] = {0};
2152 static const WCHAR chkfmt1
[] = {'%','s','=','%','s',0};
2153 static const WCHAR chkfmt2
[] = {'%','s',' ','%','s',0};
2154 static const WCHAR chkfmt3
[] = {'\\','\"','%','s','\"',0};
2155 static const WCHAR chkfmt4
[] = {'%','s','=','%','s','\"',' ','%','s','\"',0};
2157 LPWSTR
*args
= (LPWSTR
*)0xdeadcafe, pbuf
;
2161 wsprintfW(cmdline
,fmt1
,one
,two
,three
,four
);
2162 args
=CommandLineToArgvW(cmdline
,&numargs
);
2163 if (args
== NULL
&& numargs
== -1)
2165 win_skip("CommandLineToArgvW not implemented, skipping\n");
2168 ok(numargs
== 4, "expected 4 args, got %i\n",numargs
);
2169 ok(lstrcmpW(args
[0],one
)==0,"arg0 is not as expected\n");
2170 ok(lstrcmpW(args
[1],two
)==0,"arg1 is not as expected\n");
2171 ok(lstrcmpW(args
[2],three
)==0,"arg2 is not as expected\n");
2172 ok(lstrcmpW(args
[3],four
)==0,"arg3 is not as expected\n");
2174 wsprintfW(cmdline
,fmt2
,one
,two
,three
,four
);
2175 args
=CommandLineToArgvW(cmdline
,&numargs
);
2176 ok(numargs
== 5, "expected 5 args, got %i\n",numargs
);
2177 ok(args
[0][0]==0,"arg0 is not as expected\n");
2178 ok(lstrcmpW(args
[1],one
)==0,"arg1 is not as expected\n");
2179 ok(lstrcmpW(args
[2],two
)==0,"arg2 is not as expected\n");
2180 ok(lstrcmpW(args
[3],three
)==0,"arg3 is not as expected\n");
2181 ok(lstrcmpW(args
[4],four
)==0,"arg4 is not as expected\n");
2183 wsprintfW(cmdline
,fmt3
,one
,two
,three
,four
);
2184 args
=CommandLineToArgvW(cmdline
,&numargs
);
2185 ok(numargs
== 2, "expected 2 args, got %i\n",numargs
);
2186 wsprintfW(cmdline
,chkfmt1
,one
,two
);
2187 ok(lstrcmpW(args
[0],cmdline
)==0,"arg0 is not as expected\n");
2188 wsprintfW(cmdline
,chkfmt1
,three
,four
);
2189 ok(lstrcmpW(args
[1],cmdline
)==0,"arg1 is not as expected\n");
2191 wsprintfW(cmdline
,fmt4
,one
,two
,three
,four
);
2192 args
=CommandLineToArgvW(cmdline
,&numargs
);
2193 ok(numargs
== 3, "expected 3 args, got %i\n",numargs
);
2194 ok(lstrcmpW(args
[0],one
)==0,"arg0 is not as expected\n");
2195 wsprintfW(cmdline
,chkfmt2
,two
,three
);
2196 ok(lstrcmpW(args
[1],cmdline
)==0,"arg1 is not as expected\n");
2197 ok(lstrcmpW(args
[2],four
)==0,"arg2 is not as expected\n");
2199 wsprintfW(cmdline
,fmt5
,one
,two
,three
,four
);
2200 args
=CommandLineToArgvW(cmdline
,&numargs
);
2201 ok(numargs
== 2, "expected 2 args, got %i\n",numargs
);
2202 wsprintfW(cmdline
,chkfmt3
,one
);
2203 todo_wine
ok(lstrcmpW(args
[0],cmdline
)==0,"arg0 is not as expected\n");
2204 wsprintfW(cmdline
,chkfmt4
,two
,three
,four
);
2205 todo_wine
ok(lstrcmpW(args
[1],cmdline
)==0,"arg1 is not as expected\n");
2207 wsprintfW(cmdline
,fmt6
);
2208 args
=CommandLineToArgvW(cmdline
,&numargs
);
2209 ok(numargs
== 1, "expected 1 args, got %i\n",numargs
);
2211 buflen
= max(lstrlenW(args
[0])+1,256);
2212 pbuf
= HeapAlloc(GetProcessHeap(), 0, buflen
*sizeof(pbuf
[0]));
2213 GetModuleFileNameW(NULL
, pbuf
, buflen
);
2215 /* check args[0] is module file name */
2216 ok(lstrcmpW(args
[0],pbuf
)==0, "wrong path to the current executable\n");
2217 HeapFree(GetProcessHeap(), 0, pbuf
);
2221 static void test_directory(void)
2223 char path
[MAX_PATH
], newdir
[MAX_PATH
];
2227 /* copy this executable to a new folder and cd to it */
2228 sprintf(newdir
, "%s\\newfolder", tmpdir
);
2229 rc
= CreateDirectoryA( newdir
, NULL
);
2230 ok( rc
, "failed to create %s err %u\n", newdir
, GetLastError() );
2231 sprintf(path
, "%s\\%s", newdir
, path_find_file_name(argv0
));
2232 CopyFileA(argv0
, path
, FALSE
);
2233 SetCurrentDirectory(tmpdir
);
2235 sprintf(params
, "shlexec \"%s\" Exec", child_file
);
2237 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
|SEE_MASK_FLAG_NO_UI
,
2238 NULL
, path_find_file_name(argv0
), params
, NULL
);
2239 todo_wine
ok(rc
== SE_ERR_FNF
, "%s returned %d\n", shell_call
, rc
);
2241 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
|SEE_MASK_FLAG_NO_UI
,
2242 NULL
, path_find_file_name(argv0
), params
, newdir
);
2243 ok(rc
> 32, "%s returned %d\n", shell_call
, rc
);
2244 okChildInt("argcA", 4);
2245 okChildString("argvA3", "Exec");
2246 todo_wine
okChildPath("longPath", path
);
2249 RemoveDirectoryA(newdir
);
2255 myARGC
= winetest_get_mainargs(&myARGV
);
2258 doChild(myARGC
, myARGV
);
2265 test_lpFile_parsed();
2267 test_find_executable();
2272 test_dde_default_app();