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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
43 #include "wine/test.h"
45 #include "shell32_test.h"
48 static char argv0
[MAX_PATH
];
51 static char tmpdir
[MAX_PATH
];
52 static char child_file
[MAX_PATH
];
53 static DLLVERSIONINFO dllver
;
58 * ShellExecute wrappers
61 static void dump_child();
64 static void init_event(const char* child_file
)
67 event_name
=strrchr(child_file
, '\\')+1;
68 hEvent
=CreateEvent(NULL
, FALSE
, FALSE
, event_name
);
71 static void strcat_param(char* str
, const char* param
)
85 static char shell_call
[2048]="";
86 static int shell_execute(LPCSTR operation
, LPCSTR file
, LPCSTR parameters
, LPCSTR directory
)
90 strcpy(shell_call
, "ShellExecute(");
91 strcat_param(shell_call
, operation
);
92 strcat(shell_call
, ", ");
93 strcat_param(shell_call
, file
);
94 strcat(shell_call
, ", ");
95 strcat_param(shell_call
, parameters
);
96 strcat(shell_call
, ", ");
97 strcat_param(shell_call
, directory
);
98 strcat(shell_call
, ")");
99 if (winetest_debug
> 1)
100 trace("%s\n", shell_call
);
102 DeleteFile(child_file
);
103 SetLastError(0xcafebabe);
105 /* FIXME: We cannot use ShellExecuteEx() here because if there is no
106 * association it displays the 'Open With' dialog and I could not find
107 * a flag to prevent this.
109 rc
=(int)ShellExecute(NULL
, operation
, file
, parameters
, directory
,
115 wait_rc
=WaitForSingleObject(hEvent
, 60000);
116 ok(wait_rc
==WAIT_OBJECT_0
, "WaitForSingleObject returned %d\n", wait_rc
);
118 /* The child process may have changed the result file, so let profile
119 * functions know about it
121 WritePrivateProfileStringA(NULL
, NULL
, NULL
, child_file
);
128 static int shell_execute_ex(DWORD mask
, LPCSTR operation
, LPCSTR file
,
129 LPCSTR parameters
, LPCSTR directory
)
131 SHELLEXECUTEINFO sei
;
135 strcpy(shell_call
, "ShellExecuteEx(");
136 strcat_param(shell_call
, operation
);
137 strcat(shell_call
, ", ");
138 strcat_param(shell_call
, file
);
139 strcat(shell_call
, ", ");
140 strcat_param(shell_call
, parameters
);
141 strcat(shell_call
, ", ");
142 strcat_param(shell_call
, directory
);
143 strcat(shell_call
, ")");
144 if (winetest_debug
> 1)
145 trace("%s\n", shell_call
);
147 sei
.cbSize
=sizeof(sei
);
148 sei
.fMask
=SEE_MASK_NOCLOSEPROCESS
| mask
;
150 sei
.lpVerb
=operation
;
152 sei
.lpParameters
=parameters
;
153 sei
.lpDirectory
=directory
;
154 sei
.nShow
=SW_SHOWNORMAL
;
155 sei
.hInstApp
=NULL
; /* Out */
161 sei
.hProcess
=NULL
; /* Out */
163 DeleteFile(child_file
);
164 SetLastError(0xcafebabe);
165 success
=ShellExecuteEx(&sei
);
166 rc
=(int)sei
.hInstApp
;
167 ok((success
&& rc
>= 32) || (!success
&& rc
< 32),
168 "%s rc=%d and hInstApp=%d is not allowed\n", shell_call
, success
, rc
);
173 if (sei
.hProcess
!=NULL
)
175 wait_rc
=WaitForSingleObject(sei
.hProcess
, 60000);
176 ok(wait_rc
==WAIT_OBJECT_0
, "WaitForSingleObject(hProcess) returned %d\n", wait_rc
);
178 wait_rc
=WaitForSingleObject(hEvent
, 60000);
179 ok(wait_rc
==WAIT_OBJECT_0
, "WaitForSingleObject returned %d\n", wait_rc
);
181 /* The child process may have changed the result file, so let profile
182 * functions know about it
184 WritePrivateProfileStringA(NULL
, NULL
, NULL
, child_file
);
195 * Functions to create / delete associations wrappers
199 static void create_test_association(const char* extension
)
201 HKEY hkey
, hkey_shell
;
202 char class[MAX_PATH
];
205 sprintf(class, "shlexec%s", extension
);
206 rc
=RegCreateKeyEx(HKEY_CLASSES_ROOT
, extension
, 0, NULL
, 0, KEY_SET_VALUE
,
208 assert(rc
==ERROR_SUCCESS
);
209 rc
=RegSetValueEx(hkey
, NULL
, 0, REG_SZ
, (LPBYTE
) class, strlen(class)+1);
210 assert(rc
==ERROR_SUCCESS
);
213 rc
=RegCreateKeyEx(HKEY_CLASSES_ROOT
, class, 0, NULL
, 0,
214 KEY_CREATE_SUB_KEY
| KEY_ENUMERATE_SUB_KEYS
, NULL
, &hkey
, NULL
);
215 assert(rc
==ERROR_SUCCESS
);
216 rc
=RegCreateKeyEx(hkey
, "shell", 0, NULL
, 0,
217 KEY_CREATE_SUB_KEY
, NULL
, &hkey_shell
, NULL
);
218 assert(rc
==ERROR_SUCCESS
);
220 CloseHandle(hkey_shell
);
223 static void delete_test_association(const char* extension
)
225 char class[MAX_PATH
];
227 sprintf(class, "shlexec%s", extension
);
228 SHDeleteKey(HKEY_CLASSES_ROOT
, class);
229 SHDeleteKey(HKEY_CLASSES_ROOT
, extension
);
232 static void create_test_verb(const char* extension
, const char* verb
,
235 HKEY hkey_shell
, hkey_verb
, hkey_cmd
;
236 char shell
[MAX_PATH
];
240 sprintf(shell
, "shlexec%s\\shell", extension
);
241 rc
=RegOpenKeyEx(HKEY_CLASSES_ROOT
, shell
, 0,
242 KEY_CREATE_SUB_KEY
, &hkey_shell
);
243 assert(rc
==ERROR_SUCCESS
);
244 rc
=RegCreateKeyEx(hkey_shell
, verb
, 0, NULL
, 0, KEY_CREATE_SUB_KEY
,
245 NULL
, &hkey_verb
, NULL
);
246 assert(rc
==ERROR_SUCCESS
);
247 rc
=RegCreateKeyEx(hkey_verb
, "command", 0, NULL
, 0, KEY_SET_VALUE
,
248 NULL
, &hkey_cmd
, NULL
);
249 assert(rc
==ERROR_SUCCESS
);
251 cmd
=malloc(strlen(argv0
)+10+strlen(child_file
)+2+strlen(cmdtail
)+1);
252 sprintf(cmd
,"%s shlexec \"%s\" %s", argv0
, child_file
, cmdtail
);
253 rc
=RegSetValueEx(hkey_cmd
, NULL
, 0, REG_SZ
, (LPBYTE
) cmd
, strlen(cmd
)+1);
254 assert(rc
==ERROR_SUCCESS
);
257 CloseHandle(hkey_shell
);
258 CloseHandle(hkey_verb
);
259 CloseHandle(hkey_cmd
);
266 * Functions to check that the child process was started just right
267 * (borrowed from dlls/kernel32/tests/process.c)
271 static const char* encodeA(const char* str
)
273 static char encoded
[2*1024+1];
278 len
= strlen(str
) + 1;
279 if (len
>= sizeof(encoded
)/2)
281 fprintf(stderr
, "string is too long!\n");
285 for (i
= 0; i
< len
; i
++)
286 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
291 static unsigned decode_char(char c
)
293 if (c
>= '0' && c
<= '9') return c
- '0';
294 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
295 assert(c
>= 'A' && c
<= 'F');
299 static char* decodeA(const char* str
)
301 static char decoded
[1024];
305 len
= strlen(str
) / 2;
306 if (!len
--) return NULL
;
307 if (len
>= sizeof(decoded
))
309 fprintf(stderr
, "string is too long!\n");
313 for (i
= 0; i
< len
; i
++)
314 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
319 static void childPrintf(HANDLE h
, const char* fmt
, ...)
325 va_start(valist
, fmt
);
326 vsprintf(buffer
, fmt
, valist
);
328 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
331 static void doChild(int argc
, char** argv
)
338 hFile
=CreateFileA(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
339 if (hFile
== INVALID_HANDLE_VALUE
)
343 childPrintf(hFile
, "[Arguments]\n");
344 if (winetest_debug
> 2)
345 trace("argcA=%d\n", argc
);
346 childPrintf(hFile
, "argcA=%d\n", argc
);
347 for (i
= 0; i
< argc
; i
++)
349 if (winetest_debug
> 2)
350 trace("argvA%d=%s\n", i
, argv
[i
]);
351 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(argv
[i
]));
355 init_event(filename
);
360 static char* getChildString(const char* sect
, const char* key
)
365 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), child_file
);
366 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
367 assert(!(strlen(buf
) & 1));
372 static void dump_child()
374 if (winetest_debug
> 1)
380 c
=GetPrivateProfileIntA("Arguments", "argcA", -1, child_file
);
381 trace("argcA=%d\n",c
);
384 sprintf(key
, "argvA%d", i
);
385 str
=getChildString("Arguments", key
);
386 trace("%s=%s\n", key
, str
);
391 static int StrCmpPath(const char* s1
, const char* s2
)
393 if (!s1
&& !s2
) return 0;
404 if ((*s1
=='/' || *s1
=='\\') && (*s2
=='/' || *s2
=='\\'))
406 while (*s1
=='/' || *s1
=='\\')
408 while (*s2
=='/' || *s2
=='\\')
411 else if (toupper(*s1
)==toupper(*s2
))
428 static int _okChildString(const char* file
, int line
, const char* key
, const char* expected
)
431 result
=getChildString("Arguments", key
);
432 return ok_(file
, line
)(lstrcmpiA(result
, expected
) == 0,
433 "%s expected '%s', got '%s'\n", key
, expected
, result
);
436 static int _okChildPath(const char* file
, int line
, const char* key
, const char* expected
)
439 result
=getChildString("Arguments", key
);
440 return ok_(file
, line
)(StrCmpPath(result
, expected
) == 0,
441 "%s expected '%s', got '%s'\n", key
, expected
, result
);
444 static int _okChildInt(const char* file
, int line
, const char* key
, int expected
)
447 result
=GetPrivateProfileIntA("Arguments", key
, expected
, child_file
);
448 return ok_(file
, line
)(result
== expected
,
449 "%s expected %d, but got %d\n", key
, expected
, result
);
452 #define okChildString(key, expected) _okChildString(__FILE__, __LINE__, (key), (expected))
453 #define okChildPath(key, expected) _okChildPath(__FILE__, __LINE__, (key), (expected))
454 #define okChildInt(key, expected) _okChildInt(__FILE__, __LINE__, (key), (expected))
464 static const char* testfiles
[]=
466 "%s\\test file.shlexec",
467 "%s\\%%nasty%% $file.shlexec",
468 "%s\\test file.noassoc",
469 "%s\\test file.noassoc.shlexec",
470 "%s\\test file.shlexec.noassoc",
471 "%s\\test_shortcut_shlexec.lnk",
472 "%s\\test_shortcut_exe.lnk",
484 static filename_tests_t filename_tests
[]=
486 /* Test bad / nonexistent filenames */
487 {NULL
, "%s\\nonexistent.shlexec", ERROR_FILE_NOT_FOUND
, 0x1},
488 {NULL
, "%s\\nonexistent.noassoc", ERROR_FILE_NOT_FOUND
, 0x1},
491 {NULL
, "%s\\test file.shlexec", 0, 0x0},
492 {NULL
, "%s\\test file.shlexec.", 0, 0x0},
493 {NULL
, "%s\\%%nasty%% $file.shlexec", 0, 0x0},
494 {NULL
, "%s/test file.shlexec", 0, 0x0},
496 /* Test filenames with no association */
497 {NULL
, "%s\\test file.noassoc", SE_ERR_NOASSOC
, 0x0},
499 /* Test double extensions */
500 {NULL
, "%s\\test file.noassoc.shlexec", 0, 0},
501 {NULL
, "%s\\test file.shlexec.noassoc", SE_ERR_NOASSOC
, 0x0},
503 /* Test alternate verbs */
504 {"LowerL", "%s\\nonexistent.shlexec", ERROR_FILE_NOT_FOUND
, 0x1},
505 {"LowerL", "%s\\test file.noassoc", SE_ERR_NOASSOC
, 0x0},
507 {"QuotedLowerL", "%s\\test file.shlexec", 0, 0x0},
508 {"QuotedUpperL", "%s\\test file.shlexec", 0, 0x0},
513 static filename_tests_t noquotes_tests
[]=
515 /* Test unquoted '%1' thingies */
516 {"NoQuotes", "%s\\test file.shlexec", 0, 0xa},
517 {"LowerL", "%s\\test file.shlexec", 0, 0x0},
518 {"UpperL", "%s\\test file.shlexec", 0, 0x0},
523 static void test_filename()
525 char filename
[MAX_PATH
];
526 const filename_tests_t
* test
;
531 while (test
->basename
)
533 sprintf(filename
, test
->basename
, tmpdir
);
534 if (strchr(filename
, '/'))
544 rc
=shell_execute(test
->verb
, filename
, NULL
, NULL
);
547 if ((test
->todo
& 0x1)==0)
549 ok(rc
==test
->rc
, "%s failed: rc=%d err=%ld\n", shell_call
,
554 ok(rc
==test
->rc
, "%s failed: rc=%d err=%ld\n", shell_call
,
560 if ((test
->todo
& 0x2)==0)
562 okChildInt("argcA", 5);
566 okChildInt("argcA", 5);
568 verb
=(test
->verb
? test
->verb
: "Open");
569 if ((test
->todo
& 0x4)==0)
571 okChildString("argvA3", verb
);
575 okChildString("argvA3", verb
);
577 if ((test
->todo
& 0x8)==0)
579 okChildPath("argvA4", filename
);
583 okChildPath("argvA4", filename
);
590 while (test
->basename
)
592 sprintf(filename
, test
->basename
, tmpdir
);
593 rc
=shell_execute(test
->verb
, filename
, NULL
, NULL
);
596 if ((test
->todo
& 0x1)==0)
598 ok(rc
==test
->rc
, "%s failed: rc=%d err=%ld\n", shell_call
,
603 ok(rc
==test
->rc
, "%s failed: rc=%d err=%ld\n", shell_call
,
612 verb
=(test
->verb
? test
->verb
: "Open");
613 if ((test
->todo
& 0x4)==0)
615 okChildString("argvA3", verb
);
619 okChildString("argvA3", verb
);
628 space
=strchr(str
, ' ');
631 sprintf(attrib
, "argvA%d", count
);
632 if ((test
->todo
& 0x8)==0)
634 okChildPath(attrib
, str
);
638 okChildPath(attrib
, str
);
645 if ((test
->todo
& 0x2)==0)
647 okChildInt("argcA", count
);
651 okChildInt("argcA", count
);
657 if (dllver
.dwMajorVersion
!= 0)
659 /* The more recent versions of shell32.dll accept quoted filenames
660 * while older ones (e.g. 4.00) don't. Still we want to test this
661 * because IE 6 depends on the new behavior.
662 * One day we may need to check the exact version of the dll but for
663 * now making sure DllGetVersion() is present is sufficient.
665 sprintf(filename
, "\"%s\\test file.shlexec\"", tmpdir
);
666 rc
=shell_execute(NULL
, filename
, NULL
, NULL
);
667 ok(rc
>=32, "%s failed: rc=%d err=%ld\n", shell_call
, rc
,
669 okChildInt("argcA", 5);
670 okChildString("argvA3", "Open");
671 sprintf(filename
, "%s\\test file.shlexec", tmpdir
);
672 okChildPath("argvA4", filename
);
677 static filename_tests_t lnk_tests
[]=
679 /* Pass bad / nonexistent filenames as a parameter */
680 {NULL
, "%s\\nonexistent.shlexec", 0, 0xa},
681 {NULL
, "%s\\nonexistent.noassoc", 0, 0xa},
683 /* Pass regular paths as a parameter */
684 {NULL
, "%s\\test file.shlexec", 0, 0xa},
685 {NULL
, "%s/%%nasty%% $file.shlexec", 0, 0xa},
687 /* Pass filenames with no association as a parameter */
688 {NULL
, "%s\\test file.noassoc", 0, 0xa},
693 static void test_lnks()
695 char filename
[MAX_PATH
];
696 char params
[MAX_PATH
];
697 const filename_tests_t
* test
;
700 sprintf(filename
, "%s\\test_shortcut_shlexec.lnk", tmpdir
);
701 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, filename
, NULL
, NULL
);
702 ok(rc
>=32, "%s failed: rc=%d err=%ld\n", shell_call
, rc
,
704 okChildInt("argcA", 5);
705 okChildString("argvA3", "Open");
706 sprintf(filename
, "%s\\test file.shlexec", tmpdir
);
707 okChildPath("argvA4", filename
);
709 sprintf(filename
, "%s\\test_shortcut_exe.lnk", tmpdir
);
710 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, filename
, NULL
, NULL
);
711 ok(rc
>=32, "%s failed: rc=%d err=%ld\n", shell_call
, rc
,
713 okChildInt("argcA", 4);
714 okChildString("argvA3", "Lnk");
716 if (dllver
.dwMajorVersion
>=6)
719 /* Recent versions of shell32.dll accept '/'s in shortcut paths.
720 * Older versions don't or are quite buggy in this regard.
722 sprintf(filename
, "%s\\test_shortcut_exe.lnk", tmpdir
);
730 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, filename
, NULL
, NULL
);
731 ok(rc
>=32, "%s failed: rc=%d err=%ld\n", shell_call
, rc
,
733 okChildInt("argcA", 4);
734 okChildString("argvA3", "Lnk");
737 sprintf(filename
, "%s\\test_shortcut_exe.lnk", tmpdir
);
739 while (test
->basename
)
742 sprintf(params
+1, test
->basename
, tmpdir
);
744 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, filename
, params
,
748 if ((test
->todo
& 0x1)==0)
750 ok(rc
==test
->rc
, "%s failed: rc=%d err=%ld\n", shell_call
,
755 ok(rc
==test
->rc
, "%s failed: rc=%d err=%ld\n", shell_call
,
760 if ((test
->todo
& 0x2)==0)
762 okChildInt("argcA", 5);
766 okChildInt("argcA", 5);
768 if ((test
->todo
& 0x4)==0)
770 okChildString("argvA3", "Lnk");
774 okChildString("argvA3", "Lnk");
776 sprintf(params
, test
->basename
, tmpdir
);
777 if ((test
->todo
& 0x8)==0)
779 okChildPath("argvA4", params
);
783 okChildPath("argvA4", params
);
791 static void test_exes()
793 char filename
[MAX_PATH
];
797 sprintf(params
, "shlexec \"%s\" Exec", child_file
);
799 /* We need NOZONECHECKS on Win2003 to block a dialog */
800 rc
=shell_execute_ex(SEE_MASK_NOZONECHECKS
, NULL
, argv0
, params
,
802 ok(rc
>=32, "%s returned %d\n", shell_call
, rc
);
803 okChildInt("argcA", 4);
804 okChildString("argvA3", "Exec");
806 sprintf(filename
, "%s\\test file.noassoc", tmpdir
);
807 if (CopyFile(argv0
, filename
, FALSE
))
809 rc
=shell_execute(NULL
, filename
, params
, NULL
);
811 ok(rc
==SE_ERR_NOASSOC
, "%s succeeded: rc=%d\n", shell_call
, rc
);
817 static void init_test()
820 HRESULT (WINAPI
*pDllGetVersion
)(DLLVERSIONINFO
*);
821 char filename
[MAX_PATH
];
822 WCHAR lnkfile
[MAX_PATH
];
824 const char* const * testfile
;
829 hdll
=GetModuleHandleA("shell32.dll");
830 pDllGetVersion
=(void*)GetProcAddress(hdll
, "DllGetVersion");
833 dllver
.cbSize
=sizeof(dllver
);
834 pDllGetVersion(&dllver
);
835 trace("major=%ld minor=%ld build=%ld platform=%ld\n",
836 dllver
.dwMajorVersion
, dllver
.dwMinorVersion
,
837 dllver
.dwBuildNumber
, dllver
.dwPlatformID
);
841 memset(&dllver
, 0, sizeof(dllver
));
844 r
= CoInitialize(NULL
);
845 ok(SUCCEEDED(r
), "CoInitialize failed (0x%08lx)\n", r
);
849 rc
=GetModuleFileName(NULL
, argv0
, sizeof(argv0
));
850 assert(rc
!=0 && rc
<sizeof(argv0
));
851 if (GetFileAttributes(argv0
)==INVALID_FILE_ATTRIBUTES
)
853 strcat(argv0
, ".so");
854 ok(GetFileAttributes(argv0
)!=INVALID_FILE_ATTRIBUTES
,
855 "unable to find argv0!\n");
858 GetTempPathA(sizeof(tmpdir
)/sizeof(*tmpdir
), tmpdir
);
859 assert(GetTempFileNameA(tmpdir
, "wt", 0, child_file
)!=0);
860 init_event(child_file
);
862 /* Set up the test files */
868 sprintf(filename
, *testfile
, tmpdir
);
869 hfile
=CreateFile(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
870 FILE_ATTRIBUTE_NORMAL
, NULL
);
871 if (hfile
==INVALID_HANDLE_VALUE
)
873 trace("unable to create '%s': err=%ld\n", filename
, GetLastError());
880 /* Setup the test shortcuts */
881 sprintf(filename
, "%s\\test_shortcut_shlexec.lnk", tmpdir
);
882 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, lnkfile
, sizeof(lnkfile
)/sizeof(*lnkfile
));
883 desc
.description
=NULL
;
885 sprintf(filename
, "%s\\test file.shlexec", tmpdir
);
888 desc
.arguments
="ignored";
893 create_lnk(lnkfile
, &desc
, 0);
895 sprintf(filename
, "%s\\test_shortcut_exe.lnk", tmpdir
);
896 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, lnkfile
, sizeof(lnkfile
)/sizeof(*lnkfile
));
897 desc
.description
=NULL
;
901 sprintf(params
, "shlexec \"%s\" Lnk", child_file
);
902 desc
.arguments
=params
;
907 create_lnk(lnkfile
, &desc
, 0);
909 /* Create a basic association suitable for most tests */
910 create_test_association(".shlexec");
911 create_test_verb(".shlexec", "Open", "Open \"%1\"");
912 create_test_verb(".shlexec", "NoQuotes", "NoQuotes %1");
913 create_test_verb(".shlexec", "LowerL", "LowerL %l");
914 create_test_verb(".shlexec", "QuotedLowerL", "QuotedLowerL \"%l\"");
915 create_test_verb(".shlexec", "UpperL", "UpperL %L");
916 create_test_verb(".shlexec", "QuotedUpperL", "QuotedUpperL \"%L\"");
919 static void cleanup_test()
921 char filename
[MAX_PATH
];
922 const char* const * testfile
;
924 /* Delete the test files */
928 sprintf(filename
, *testfile
, tmpdir
);
929 DeleteFile(filename
);
932 DeleteFile(child_file
);
934 /* Delete the test association */
935 delete_test_association(".shlexec");
945 myARGC
= winetest_get_mainargs(&myARGV
);
948 doChild(myARGC
, myARGV
);