ReactOS  0.4.15-dev-1184-g23e04ae
shlexec.c
Go to the documentation of this file.
1 /*
2  * Unit test of the ShellExecute function.
3  *
4  * Copyright 2005, 2016 Francois Gouget for CodeWeavers
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 /* TODO:
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
27  * in the PATH
28  * - test associations that use %l, %L or "%1" instead of %1
29  * - ShellExecuteEx() also calls SetLastError() with meaningful values which
30  * we could check
31  */
32 
33 #include <stdio.h>
34 #include <assert.h>
35 
36 #include "wtypes.h"
37 #include "winbase.h"
38 #include "windef.h"
39 #include "shellapi.h"
40 #include "shlwapi.h"
41 #include "ddeml.h"
42 
43 #include "wine/heap.h"
44 #include "wine/test.h"
45 
46 #include "shell32_test.h"
47 
48 
49 static char argv0[MAX_PATH];
50 static int myARGC;
51 static char** myARGV;
52 static char tmpdir[MAX_PATH];
53 static char child_file[MAX_PATH];
58 
59 
60 /***
61  *
62  * Helpers to read from / write to the child process results file.
63  * (borrowed from dlls/kernel32/tests/process.c)
64  *
65  ***/
66 
67 static const char* encodeA(const char* str)
68 {
69  static char encoded[2*1024+1];
70  char* ptr;
71  size_t len,i;
72 
73  if (!str) return "";
74  len = strlen(str) + 1;
75  if (len >= sizeof(encoded)/2)
76  {
77  fprintf(stderr, "string is too long!\n");
78  assert(0);
79  }
80  ptr = encoded;
81  for (i = 0; i < len; i++)
82  sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
83  ptr[2 * len] = '\0';
84  return ptr;
85 }
86 
87 static unsigned decode_char(char c)
88 {
89  if (c >= '0' && c <= '9') return c - '0';
90  if (c >= 'a' && c <= 'f') return c - 'a' + 10;
91  assert(c >= 'A' && c <= 'F');
92  return c - 'A' + 10;
93 }
94 
95 static char* decodeA(const char* str)
96 {
97  static char decoded[1024];
98  char* ptr;
99  size_t len,i;
100 
101  len = strlen(str) / 2;
102  if (!len--) return NULL;
103  if (len >= sizeof(decoded))
104  {
105  fprintf(stderr, "string is too long!\n");
106  assert(0);
107  }
108  ptr = decoded;
109  for (i = 0; i < len; i++)
110  ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
111  ptr[len] = '\0';
112  return ptr;
113 }
114 
115 static void WINAPIV WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...)
116 {
118  char buffer[1024];
119  DWORD w;
120 
125 }
126 
127 static char* getChildString(const char* sect, const char* key)
128 {
129  char buf[1024];
130  char* ret;
131 
132  GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), child_file);
133  if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
134  assert(!(strlen(buf) & 1));
135  ret = decodeA(buf);
136  return ret;
137 }
138 
139 
140 /***
141  *
142  * Child code
143  *
144  ***/
145 
146 #define CHILD_DDE_TIMEOUT 2500
147 static DWORD ddeInst;
148 static HSZ hszTopic;
151 
152 /* Handle DDE for doChild() and test_dde_default_app() */
153 static HDDEDATA CALLBACK ddeCb(UINT uType, UINT uFmt, HCONV hConv,
154  HSZ hsz1, HSZ hsz2, HDDEDATA hData,
155  ULONG_PTR dwData1, ULONG_PTR dwData2)
156 {
157  DWORD size = 0;
158 
159  if (winetest_debug > 2)
160  trace("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
161  uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
162 
163  switch (uType)
164  {
165  case XTYP_CONNECT:
166  if (!DdeCmpStringHandles(hsz1, hszTopic))
167  {
169  ok(size < MAX_PATH, "got size %d\n", size);
170  assert(size < MAX_PATH);
171  return (HDDEDATA)TRUE;
172  }
173  return (HDDEDATA)FALSE;
174 
175  case XTYP_EXECUTE:
176  size = DdeGetData(hData, (LPBYTE)ddeExec, MAX_PATH, 0);
177  ok(size < MAX_PATH, "got size %d\n", size);
178  assert(size < MAX_PATH);
179  DdeFreeDataHandle(hData);
181  PostQuitMessage(0);
182  return (HDDEDATA)DDE_FACK;
183 
184  default:
185  return NULL;
186  }
187 }
188 
189 static HANDLE hEvent;
190 static void init_event(const char* child_file)
191 {
192  char* event_name;
193  event_name=strrchr(child_file, '\\')+1;
194  hEvent=CreateEventA(NULL, FALSE, FALSE, event_name);
195 }
196 
197 /*
198  * This is just to make sure the child won't run forever stuck in a
199  * GetMessage() loop when DDE fails for some reason.
200  */
201 static void CALLBACK childTimeout(HWND wnd, UINT msg, UINT_PTR timer, DWORD time)
202 {
203  trace("childTimeout called\n");
204 
205  PostQuitMessage(0);
206 }
207 
208 static void doChild(int argc, char** argv)
209 {
210  char *filename, buffer[MAX_PATH];
211  HANDLE hFile, map;
212  int i;
213  UINT_PTR timer;
214 
215  filename=argv[2];
218  return;
219 
220  /* Arguments */
221  childPrintf(hFile, "[Child]\r\n");
222  if (winetest_debug > 2)
223  {
224  trace("cmdlineA='%s'\n", GetCommandLineA());
225  trace("argcA=%d\n", argc);
226  }
227  childPrintf(hFile, "cmdlineA=%s\r\n", encodeA(GetCommandLineA()));
228  childPrintf(hFile, "argcA=%d\r\n", argc);
229  for (i = 0; i < argc; i++)
230  {
231  if (winetest_debug > 2)
232  trace("argvA%d='%s'\n", i, argv[i]);
233  childPrintf(hFile, "argvA%d=%s\r\n", i, encodeA(argv[i]));
234  }
236  childPrintf(hFile, "longPath=%s\r\n", encodeA(buffer));
237 
238  /* Check environment variable inheritance */
239  *buffer = '\0';
240  SetLastError(0);
241  GetEnvironmentVariableA("ShlexecVar", buffer, sizeof(buffer));
242  childPrintf(hFile, "ShlexecVarLE=%d\r\n", GetLastError());
243  childPrintf(hFile, "ShlexecVar=%s\r\n", encodeA(buffer));
244 
245  map = OpenFileMappingA(FILE_MAP_READ, FALSE, "winetest_shlexec_dde_map");
246  if (map != NULL)
247  {
248  HANDLE dde_ready;
249  char *shared_block = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 4096);
250  CloseHandle(map);
251  if (shared_block[0] != '\0' || shared_block[1] != '\0')
252  {
253  HDDEDATA hdde;
254  HSZ hszApplication;
255  MSG msg;
256  UINT rc;
257 
259  ddeInst = 0;
262  ok(rc == DMLERR_NO_ERROR, "DdeInitializeA() returned %d\n", rc);
263  hszApplication = DdeCreateStringHandleA(ddeInst, shared_block, CP_WINANSI);
264  ok(hszApplication != NULL, "DdeCreateStringHandleA(%s) = NULL\n", shared_block);
265  shared_block += strlen(shared_block) + 1;
267  ok(hszTopic != NULL, "DdeCreateStringHandleA(%s) = NULL\n", shared_block);
268  hdde = DdeNameService(ddeInst, hszApplication, 0, DNS_REGISTER | DNS_FILTEROFF);
269  ok(hdde != NULL, "DdeNameService() failed le=%u\n", GetLastError());
270 
272 
273  dde_ready = OpenEventA(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready");
274  SetEvent(dde_ready);
275  CloseHandle(dde_ready);
276 
277  while (GetMessageA(&msg, NULL, 0, 0))
278  {
279  if (winetest_debug > 2)
280  trace("msg %d lParam=%ld wParam=%lu\n", msg.message, msg.lParam, msg.wParam);
282  }
283 
284  Sleep(500);
285  KillTimer(NULL, timer);
286  hdde = DdeNameService(ddeInst, hszApplication, 0, DNS_UNREGISTER);
287  ok(hdde != NULL, "DdeNameService() failed le=%u\n", GetLastError());
288  ok(DdeFreeStringHandle(ddeInst, hszTopic), "DdeFreeStringHandle(topic)\n");
289  ok(DdeFreeStringHandle(ddeInst, hszApplication), "DdeFreeStringHandle(application)\n");
290  ok(DdeUninitialize(ddeInst), "DdeUninitialize() failed\n");
291  }
292  else
293  {
294  dde_ready = OpenEventA(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready");
295  SetEvent(dde_ready);
296  CloseHandle(dde_ready);
297  }
298 
299  UnmapViewOfFile(shared_block);
300 
301  childPrintf(hFile, "ddeExec=%s\r\n", encodeA(ddeExec));
302  }
303 
304  childPrintf(hFile, "Failures=%d\r\n", winetest_get_failures());
306 
308  SetEvent(hEvent);
310 }
311 
312 static void dump_child_(const char* file, int line)
313 {
314  if (winetest_debug > 1)
315  {
316  char key[18];
317  char* str;
318  int i, c;
319 
320  str=getChildString("Child", "cmdlineA");
321  trace_(file, line)("cmdlineA='%s'\n", str);
322  c=GetPrivateProfileIntA("Child", "argcA", -1, child_file);
323  trace_(file, line)("argcA=%d\n",c);
324  for (i=0;i<c;i++)
325  {
326  sprintf(key, "argvA%d", i);
327  str=getChildString("Child", key);
328  trace_(file, line)("%s='%s'\n", key, str);
329  }
330 
331  c=GetPrivateProfileIntA("Child", "ShlexecVarLE", -1, child_file);
332  trace_(file, line)("ShlexecVarLE=%d\n", c);
333  str=getChildString("Child", "ShlexecVar");
334  trace_(file, line)("ShlexecVar='%s'\n", str);
335 
336  c=GetPrivateProfileIntA("Child", "Failures", -1, child_file);
337  trace_(file, line)("Failures=%d\n", c);
338  }
339 }
340 
341 
342 /***
343  *
344  * Helpers to check the ShellExecute() / child process results.
345  *
346  ***/
347 
348 static char shell_call[2048];
349 static void WINAPIV WINETEST_PRINTF_ATTR(2,3) _okShell(int condition, const char *msg, ...)
350 {
352  char buffer[2048];
353 
355  strcat(buffer, " ");
359  winetest_ok(condition, "%s", buffer);
360 }
361 #define okShell_(file, line) (winetest_set_location(file, line), 0) ? (void)0 : _okShell
362 #define okShell okShell_(__FILE__, __LINE__)
363 
364 static char assoc_desc[2048];
366 {
367  *assoc_desc = '\0';
368 }
369 
370 static void okChildString_(const char* file, int line, const char* key, const char* expected, const char* bad)
371 {
372  char* result;
373  result=getChildString("Child", key);
374  if (!result)
375  {
376  okShell_(file, line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected);
377  return;
378  }
380  broken(lstrcmpiA(result, bad) == 0),
381  "%s expected '%s', got '%s'\n", key, expected, result);
382 }
383 #define okChildString(key, expected) okChildString_(__FILE__, __LINE__, (key), (expected), (expected))
384 #define okChildStringBroken(key, expected, broken) okChildString_(__FILE__, __LINE__, (key), (expected), (broken))
385 
386 static int StrCmpPath(const char* s1, const char* s2)
387 {
388  if (!s1 && !s2) return 0;
389  if (!s2) return 1;
390  if (!s1) return -1;
391  while (*s1)
392  {
393  if (!*s2)
394  {
395  if (*s1=='.')
396  s1++;
397  return (*s1-*s2);
398  }
399  if ((*s1=='/' || *s1=='\\') && (*s2=='/' || *s2=='\\'))
400  {
401  while (*s1=='/' || *s1=='\\')
402  s1++;
403  while (*s2=='/' || *s2=='\\')
404  s2++;
405  }
406  else if (toupper(*s1)==toupper(*s2))
407  {
408  s1++;
409  s2++;
410  }
411  else
412  {
413  return (*s1-*s2);
414  }
415  }
416  if (*s2=='.')
417  s2++;
418  if (*s2)
419  return -1;
420  return 0;
421 }
422 
423 static void okChildPath_(const char* file, int line, const char* key, const char* expected)
424 {
425  char* result;
426  int equal, shortequal;
427  result=getChildString("Child", key);
428  if (!result)
429  {
430  okShell_(file,line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected);
431  return;
432  }
433  shortequal = FALSE;
434  equal = (StrCmpPath(result, expected) == 0);
435  if (!equal)
436  {
437  char altpath[MAX_PATH];
438  DWORD rc = GetLongPathNameA(expected, altpath, sizeof(altpath));
439  if (0 < rc && rc < sizeof(altpath))
440  equal = (StrCmpPath(result, altpath) == 0);
441  if (!equal)
442  {
443  rc = GetShortPathNameA(expected, altpath, sizeof(altpath));
444  if (0 < rc && rc < sizeof(altpath))
445  shortequal = (StrCmpPath(result, altpath) == 0);
446  }
447  }
448  okShell_(file,line)(equal || broken(shortequal) /* XP SP1 */,
449  "%s expected '%s', got '%s'\n", key, expected, result);
450 }
451 #define okChildPath(key, expected) okChildPath_(__FILE__, __LINE__, (key), (expected))
452 
453 static void okChildInt_(const char* file, int line, const char* key, int expected)
454 {
455  INT result;
458  "%s expected %d, but got %d\n", key, expected, result);
459 }
460 #define okChildInt(key, expected) okChildInt_(__FILE__, __LINE__, (key), (expected))
461 
462 static void okChildIntBroken_(const char* file, int line, const char* key, int expected)
463 {
464  INT result;
467  "%s expected %d, but got %d\n", key, expected, result);
468 }
469 #define okChildIntBroken(key, expected) okChildIntBroken_(__FILE__, __LINE__, (key), (expected))
470 
471 
472 /***
473  *
474  * ShellExecute wrappers
475  *
476  ***/
477 
478 static void strcat_param(char* str, const char* name, const char* param)
479 {
480  if (param)
481  {
482  if (str[strlen(str)-1] == '"')
483  strcat(str, ", ");
484  strcat(str, name);
485  strcat(str, "=\"");
486  strcat(str, param);
487  strcat(str, "\"");
488  }
489 }
490 
491 static int _todo_wait = 0;
492 #define todo_wait for (_todo_wait = 1; _todo_wait; _todo_wait = 0)
493 
494 static int bad_shellexecute = 0;
495 
496 static INT_PTR shell_execute_(const char* file, int line, LPCSTR verb, LPCSTR filename, LPCSTR parameters, LPCSTR directory)
497 {
498  INT_PTR rc, rcEmpty = 0;
499 
500  if(!verb)
501  rcEmpty = shell_execute_(file, line, "", filename, parameters, directory);
502 
503  strcpy(shell_call, "ShellExecute(");
504  strcat_param(shell_call, "verb", verb);
505  strcat_param(shell_call, "file", filename);
506  strcat_param(shell_call, "params", parameters);
508  strcat(shell_call, ")");
510  if (winetest_debug > 1)
511  trace_(file, line)("Called %s\n", shell_call);
512 
514  SetLastError(0xcafebabe);
515 
516  /* FIXME: We cannot use ShellExecuteEx() here because if there is no
517  * association it displays the 'Open With' dialog and I could not find
518  * a flag to prevent this.
519  */
520  rc=(INT_PTR)ShellExecuteA(NULL, verb, filename, parameters, directory, SW_HIDE);
521 
522  if (rc > 32)
523  {
524  int wait_rc;
525  wait_rc=WaitForSingleObject(hEvent, 5000);
526  if (wait_rc == WAIT_TIMEOUT)
527  {
528  HWND wnd = FindWindowA("#32770", "Windows");
529  if (!wnd)
530  wnd = FindWindowA("Shell_Flyout", "");
531  if (wnd != NULL)
532  {
533  SendMessageA(wnd, WM_CLOSE, 0, 0);
534  win_skip("Skipping shellexecute of file with unassociated extension\n");
536  rc = SE_ERR_NOASSOC;
537  }
538  }
540  okShell_(file, line)(wait_rc==WAIT_OBJECT_0 || rc <= 32,
541  "WaitForSingleObject returned %d\n", wait_rc);
542  }
543  /* The child process may have changed the result file, so let profile
544  * functions know about it
545  */
548  {
549  int c;
551  c = GetPrivateProfileIntA("Child", "Failures", -1, child_file);
552  if (c > 0)
554  okChildInt_(file, line, "ShlexecVarLE", 0);
555  okChildString_(file, line, "ShlexecVar", "Present", "Present");
556  }
557 
558  if(!verb)
559  {
560  if (rc != rcEmpty && rcEmpty == SE_ERR_NOASSOC) /* NT4 */
561  bad_shellexecute = 1;
562  okShell_(file, line)(rc == rcEmpty ||
563  broken(rc != rcEmpty && rcEmpty == SE_ERR_NOASSOC) /* NT4 */,
564  "Got different return value with empty string: %lu %lu\n", rc, rcEmpty);
565  }
566 
567  return rc;
568 }
569 #define shell_execute(verb, filename, parameters, directory) \
570  shell_execute_(__FILE__, __LINE__, verb, filename, parameters, directory)
571 
572 static INT_PTR shell_execute_ex_(const char* file, int line,
574  LPCSTR parameters, LPCSTR directory,
575  LPCSTR class)
576 {
577  char smask[11];
578  SHELLEXECUTEINFOA sei;
579  BOOL success;
580  INT_PTR rc;
581 
582  /* Add some flags so we can wait for the child process */
584 
585  strcpy(shell_call, "ShellExecuteEx(");
586  sprintf(smask, "0x%x", mask);
587  strcat_param(shell_call, "mask", smask);
588  strcat_param(shell_call, "verb", verb);
589  strcat_param(shell_call, "file", filename);
590  strcat_param(shell_call, "params", parameters);
592  strcat_param(shell_call, "class", class);
593  strcat(shell_call, ")");
595  if (winetest_debug > 1)
596  trace_(file, line)("Called %s\n", shell_call);
597 
598  sei.cbSize=sizeof(sei);
599  sei.fMask=mask;
600  sei.hwnd=NULL;
601  sei.lpVerb=verb;
602  sei.lpFile=filename;
603  sei.lpParameters=parameters;
605  sei.nShow=SW_SHOWNORMAL;
606  sei.hInstApp=NULL; /* Out */
607  sei.lpIDList=NULL;
608  sei.lpClass=class;
609  sei.hkeyClass=NULL;
610  sei.dwHotKey=0;
611  U(sei).hIcon=NULL;
612  sei.hProcess=(HANDLE)0xdeadbeef; /* Out */
613 
615  SetLastError(0xcafebabe);
616  success=ShellExecuteExA(&sei);
617  rc=(INT_PTR)sei.hInstApp;
618  okShell_(file, line)((success && rc > 32) || (!success && rc <= 32),
619  "rc=%d and hInstApp=%ld is not allowed\n",
620  success, rc);
621 
622  if (rc > 32)
623  {
624  DWORD wait_rc, rc;
625  if (sei.hProcess!=NULL)
626  {
627  wait_rc=WaitForSingleObject(sei.hProcess, 5000);
628  okShell_(file, line)(wait_rc==WAIT_OBJECT_0,
629  "WaitForSingleObject(hProcess) returned %d\n",
630  wait_rc);
631  wait_rc = GetExitCodeProcess(sei.hProcess, &rc);
632  okShell_(file, line)(wait_rc, "GetExitCodeProcess() failed le=%u\n", GetLastError());
634  okShell_(file, line)(rc == 0, "child returned %u\n", rc);
635  CloseHandle(sei.hProcess);
636  }
637  wait_rc=WaitForSingleObject(hEvent, 5000);
639  okShell_(file, line)(wait_rc==WAIT_OBJECT_0,
640  "WaitForSingleObject returned %d\n", wait_rc);
641  }
642  else
643  okShell_(file, line)(sei.hProcess==NULL,
644  "returned a process handle %p\n", sei.hProcess);
645 
646  /* The child process may have changed the result file, so let profile
647  * functions know about it
648  */
651  {
652  int c;
654  c = GetPrivateProfileIntA("Child", "Failures", -1, child_file);
655  if (c > 0)
657  /* When NOZONECHECKS is specified the environment variables are not
658  * inherited if the process does not have elevated privileges.
659  */
661  {
662  okChildInt_(file, line, "ShlexecVarLE", 203);
663  okChildString_(file, line, "ShlexecVar", "", "");
664  }
665  else
666  {
667  okChildInt_(file, line, "ShlexecVarLE", 0);
668  okChildString_(file, line, "ShlexecVar", "Present", "Present");
669  }
670  }
671 
672  return rc;
673 }
674 #define shell_execute_ex(mask, verb, filename, parameters, directory, class) \
675  shell_execute_ex_(__FILE__, __LINE__, mask, verb, filename, parameters, directory, class)
676 
677 
678 /***
679  *
680  * Functions to create / delete associations wrappers
681  *
682  ***/
683 
684 static BOOL create_test_class(const char* class, BOOL protocol)
685 {
686  HKEY hkey, hkey_shell;
687  LONG rc;
688 
689  rc = RegCreateKeyExA(HKEY_CLASSES_ROOT, class, 0, NULL, 0,
691  &hkey, NULL);
692  ok(rc == ERROR_SUCCESS || rc == ERROR_ACCESS_DENIED,
693  "could not create class %s (rc=%d)\n", class, rc);
694  if (rc != ERROR_SUCCESS)
695  return FALSE;
696 
697  if (protocol)
698  {
699  rc = RegSetValueExA(hkey, "URL Protocol", 0, REG_SZ, (LPBYTE)"", 1);
700  ok(rc == ERROR_SUCCESS, "RegSetValueEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc);
701  }
702 
703  rc = RegCreateKeyExA(hkey, "shell", 0, NULL, 0,
704  KEY_CREATE_SUB_KEY, NULL, &hkey_shell, NULL);
705  ok(rc == ERROR_SUCCESS, "RegCreateKeyEx 'shell' failed, expected ERROR_SUCCESS, got %d\n", rc);
706 
707  CloseHandle(hkey);
708  CloseHandle(hkey_shell);
709  return TRUE;
710 }
711 
712 static BOOL create_test_association(const char* extension)
713 {
714  HKEY hkey;
715  char class[MAX_PATH];
716  LONG rc;
717 
718  sprintf(class, "shlexec%s", extension);
719  rc=RegCreateKeyExA(HKEY_CLASSES_ROOT, extension, 0, NULL, 0, KEY_SET_VALUE,
720  NULL, &hkey, NULL);
721  ok(rc == ERROR_SUCCESS || rc == ERROR_ACCESS_DENIED,
722  "could not create association %s (rc=%d)\n", class, rc);
723  if (rc != ERROR_SUCCESS)
724  return FALSE;
725 
726  rc=RegSetValueExA(hkey, NULL, 0, REG_SZ, (LPBYTE) class, strlen(class)+1);
727  ok(rc==ERROR_SUCCESS, "RegSetValueEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc);
728  CloseHandle(hkey);
729 
730  return create_test_class(class, FALSE);
731 }
732 
733 /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */
734 static LSTATUS myRegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
735 {
736  LONG ret;
737  DWORD dwMaxSubkeyLen, dwMaxValueLen;
738  DWORD dwMaxLen, dwSize;
739  CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
740  HKEY hSubKey = hKey;
741 
742  if(lpszSubKey)
743  {
744  ret = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
745  if (ret) return ret;
746  }
747 
748  /* Get highest length for keys, values */
749  ret = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL,
750  &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
751  if (ret) goto cleanup;
752 
753  dwMaxSubkeyLen++;
754  dwMaxValueLen++;
755  dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
756  if (dwMaxLen > ARRAY_SIZE(szNameBuf))
757  {
758  /* Name too big: alloc a buffer for it */
759  if (!(lpszName = heap_alloc(dwMaxLen*sizeof(CHAR))))
760  {
762  goto cleanup;
763  }
764  }
765 
766 
767  /* Recursively delete all the subkeys */
768  while (TRUE)
769  {
770  dwSize = dwMaxLen;
771  if (RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL,
772  NULL, NULL, NULL)) break;
773 
774  ret = myRegDeleteTreeA(hSubKey, lpszName);
775  if (ret) goto cleanup;
776  }
777 
778  if (lpszSubKey)
779  ret = RegDeleteKeyA(hKey, lpszSubKey);
780  else
781  while (TRUE)
782  {
783  dwSize = dwMaxLen;
784  if (RegEnumValueA(hKey, 0, lpszName, &dwSize,
785  NULL, NULL, NULL, NULL)) break;
786 
787  ret = RegDeleteValueA(hKey, lpszName);
788  if (ret) goto cleanup;
789  }
790 
791 cleanup:
792  /* Free buffer if allocated */
793  if (lpszName != szNameBuf)
794  heap_free(lpszName);
795  if(lpszSubKey)
796  RegCloseKey(hSubKey);
797  return ret;
798 }
799 
800 static void delete_test_class(const char* classname)
801 {
803 }
804 
805 static void delete_test_association(const char* extension)
806 {
807  char classname[MAX_PATH];
808 
809  sprintf(classname, "shlexec%s", extension);
812 }
813 
814 static void create_test_verb_dde(const char* classname, const char* verb,
815  int rawcmd, const char* cmdtail, const char *ddeexec,
816  const char *application, const char *topic,
817  const char *ifexec)
818 {
819  HKEY hkey_shell, hkey_verb, hkey_cmd;
820  char shell[MAX_PATH];
821  char* cmd;
822  LONG rc;
823 
824  strcpy(assoc_desc, " Assoc ");
825  strcat_param(assoc_desc, "class", classname);
826  strcat_param(assoc_desc, "verb", verb);
827  sprintf(shell, "%d", rawcmd);
828  strcat_param(assoc_desc, "rawcmd", shell);
829  strcat_param(assoc_desc, "cmdtail", cmdtail);
830  strcat_param(assoc_desc, "ddeexec", ddeexec);
831  strcat_param(assoc_desc, "app", application);
832  strcat_param(assoc_desc, "topic", topic);
833  strcat_param(assoc_desc, "ifexec", ifexec);
834 
835  sprintf(shell, "%s\\shell", classname);
837  KEY_CREATE_SUB_KEY, &hkey_shell);
838  ok(rc == ERROR_SUCCESS, "%s key creation failed with %d\n", shell, rc);
839 
840  rc=RegCreateKeyExA(hkey_shell, verb, 0, NULL, 0, KEY_CREATE_SUB_KEY,
841  NULL, &hkey_verb, NULL);
842  ok(rc == ERROR_SUCCESS, "%s verb key creation failed with %d\n", verb, rc);
843 
844  rc=RegCreateKeyExA(hkey_verb, "command", 0, NULL, 0, KEY_SET_VALUE,
845  NULL, &hkey_cmd, NULL);
846  ok(rc == ERROR_SUCCESS, "\'command\' key creation failed with %d\n", rc);
847 
848  if (rawcmd)
849  {
850  rc=RegSetValueExA(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmdtail, strlen(cmdtail)+1);
851  }
852  else
853  {
854  cmd = heap_alloc(strlen(argv0) + 10 + strlen(child_file) + 2 + strlen(cmdtail) + 1);
855  sprintf(cmd,"%s shlexec \"%s\" %s", argv0, child_file, cmdtail);
856  rc=RegSetValueExA(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmd, strlen(cmd)+1);
857  ok(rc == ERROR_SUCCESS, "setting command failed with %d\n", rc);
858  heap_free(cmd);
859  }
860 
861  if (ddeexec)
862  {
863  HKEY hkey_ddeexec, hkey_application, hkey_topic, hkey_ifexec;
864 
865  rc=RegCreateKeyExA(hkey_verb, "ddeexec", 0, NULL, 0, KEY_SET_VALUE |
866  KEY_CREATE_SUB_KEY, NULL, &hkey_ddeexec, NULL);
867  ok(rc == ERROR_SUCCESS, "\'ddeexec\' key creation failed with %d\n", rc);
868  rc=RegSetValueExA(hkey_ddeexec, NULL, 0, REG_SZ, (LPBYTE)ddeexec,
869  strlen(ddeexec)+1);
870  ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
871 
872  if (application)
873  {
874  rc=RegCreateKeyExA(hkey_ddeexec, "application", 0, NULL, 0, KEY_SET_VALUE,
875  NULL, &hkey_application, NULL);
876  ok(rc == ERROR_SUCCESS, "\'application\' key creation failed with %d\n", rc);
877 
878  rc=RegSetValueExA(hkey_application, NULL, 0, REG_SZ, (LPBYTE)application,
879  strlen(application)+1);
880  ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
881  CloseHandle(hkey_application);
882  }
883  if (topic)
884  {
885  rc=RegCreateKeyExA(hkey_ddeexec, "topic", 0, NULL, 0, KEY_SET_VALUE,
886  NULL, &hkey_topic, NULL);
887  ok(rc == ERROR_SUCCESS, "\'topic\' key creation failed with %d\n", rc);
888  rc=RegSetValueExA(hkey_topic, NULL, 0, REG_SZ, (LPBYTE)topic,
889  strlen(topic)+1);
890  ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
891  CloseHandle(hkey_topic);
892  }
893  if (ifexec)
894  {
895  rc=RegCreateKeyExA(hkey_ddeexec, "ifexec", 0, NULL, 0, KEY_SET_VALUE,
896  NULL, &hkey_ifexec, NULL);
897  ok(rc == ERROR_SUCCESS, "\'ifexec\' key creation failed with %d\n", rc);
898  rc=RegSetValueExA(hkey_ifexec, NULL, 0, REG_SZ, (LPBYTE)ifexec,
899  strlen(ifexec)+1);
900  ok(rc == ERROR_SUCCESS, "set value failed with %d\n", rc);
901  CloseHandle(hkey_ifexec);
902  }
903  CloseHandle(hkey_ddeexec);
904  }
905 
906  CloseHandle(hkey_shell);
907  CloseHandle(hkey_verb);
908  CloseHandle(hkey_cmd);
909 }
910 
911 /* Creates a class' non-DDE test verb.
912  * This function is meant to be used to create long term test verbs and thus
913  * does not trace them.
914  */
915 static void create_test_verb(const char* classname, const char* verb,
916  int rawcmd, const char* cmdtail)
917 {
918  create_test_verb_dde(classname, verb, rawcmd, cmdtail, NULL, NULL,
919  NULL, NULL);
921 }
922 
923 
924 /***
925  *
926  * GetLongPathNameA equivalent that supports Win95 and WinNT
927  *
928  ***/
929 
930 static DWORD get_long_path_name(const char* shortpath, char* longpath, DWORD longlen)
931 {
932  char tmplongpath[MAX_PATH];
933  const char* p;
934  DWORD sp = 0, lp = 0;
935  DWORD tmplen;
936  WIN32_FIND_DATAA wfd;
937  HANDLE goit;
938 
939  if (!shortpath || !shortpath[0])
940  return 0;
941 
942  if (shortpath[1] == ':')
943  {
944  tmplongpath[0] = shortpath[0];
945  tmplongpath[1] = ':';
946  lp = sp = 2;
947  }
948 
949  while (shortpath[sp])
950  {
951  /* check for path delimiters and reproduce them */
952  if (shortpath[sp] == '\\' || shortpath[sp] == '/')
953  {
954  if (!lp || tmplongpath[lp-1] != '\\')
955  {
956  /* strip double "\\" */
957  tmplongpath[lp++] = '\\';
958  }
959  tmplongpath[lp] = 0; /* terminate string */
960  sp++;
961  continue;
962  }
963 
964  p = shortpath + sp;
965  if (sp == 0 && p[0] == '.' && (p[1] == '/' || p[1] == '\\'))
966  {
967  tmplongpath[lp++] = *p++;
968  tmplongpath[lp++] = *p++;
969  }
970  for (; *p && *p != '/' && *p != '\\'; p++);
971  tmplen = p - (shortpath + sp);
972  lstrcpynA(tmplongpath + lp, shortpath + sp, tmplen + 1);
973  /* Check if the file exists and use the existing file name */
974  goit = FindFirstFileA(tmplongpath, &wfd);
975  if (goit == INVALID_HANDLE_VALUE)
976  return 0;
977  FindClose(goit);
978  strcpy(tmplongpath + lp, wfd.cFileName);
979  lp += strlen(tmplongpath + lp);
980  sp += tmplen;
981  }
982  tmplen = strlen(shortpath) - 1;
983  if ((shortpath[tmplen] == '/' || shortpath[tmplen] == '\\') &&
984  (tmplongpath[lp - 1] != '/' && tmplongpath[lp - 1] != '\\'))
985  tmplongpath[lp++] = shortpath[tmplen];
986  tmplongpath[lp] = 0;
987 
988  tmplen = strlen(tmplongpath) + 1;
989  if (tmplen <= longlen)
990  {
991  strcpy(longpath, tmplongpath);
992  tmplen--; /* length without 0 */
993  }
994 
995  return tmplen;
996 }
997 
998 
999 /***
1000  *
1001  * Tests
1002  *
1003  ***/
1004 
1005 static const char* testfiles[]=
1006 {
1007  "%s\\test file.shlexec",
1008  "%s\\%%nasty%% $file.shlexec",
1009  "%s\\test file.noassoc",
1010  "%s\\test file.noassoc.shlexec",
1011  "%s\\test file.shlexec.noassoc",
1012  "%s\\test_shortcut_shlexec.lnk",
1013  "%s\\test_shortcut_exe.lnk",
1014  "%s\\test file.shl",
1015  "%s\\test file.shlfoo",
1016  "%s\\test file.sha",
1017  "%s\\test file.sfe",
1018  "%s\\test file.shlproto",
1019  "%s\\masked file.shlexec",
1020  "%s\\masked",
1021  "%s\\test file.sde",
1022  "%s\\test file.exe",
1023  "%s\\test2.exe",
1024  "%s\\simple.shlexec",
1025  "%s\\drawback_file.noassoc",
1026  "%s\\drawback_file.noassoc foo.shlexec",
1027  "%s\\drawback_nonexist.noassoc foo.shlexec",
1028  NULL
1029 };
1030 
1031 typedef struct
1032 {
1033  const char* verb;
1034  const char* basename;
1035  int todo;
1038 
1040 {
1041  /* Test bad / nonexistent filenames */
1042  {NULL, "%s\\nonexistent.shlexec", 0x0, SE_ERR_FNF},
1043  {NULL, "%s\\nonexistent.noassoc", 0x0, SE_ERR_FNF},
1044 
1045  /* Standard tests */
1046  {NULL, "%s\\test file.shlexec", 0x0, 33},
1047  {NULL, "%s\\test file.shlexec.", 0x0, 33},
1048  {NULL, "%s\\%%nasty%% $file.shlexec", 0x0, 33},
1049  {NULL, "%s/test file.shlexec", 0x0, 33},
1050 
1051  /* Test filenames with no association */
1052  {NULL, "%s\\test file.noassoc", 0x0, SE_ERR_NOASSOC},
1053 
1054  /* Test double extensions */
1055  {NULL, "%s\\test file.noassoc.shlexec", 0x0, 33},
1056  {NULL, "%s\\test file.shlexec.noassoc", 0x0, SE_ERR_NOASSOC},
1057 
1058  /* Test alternate verbs */
1059  {"LowerL", "%s\\nonexistent.shlexec", 0x0, SE_ERR_FNF},
1060  {"LowerL", "%s\\test file.noassoc", 0x0, SE_ERR_NOASSOC},
1061 
1062  {"QuotedLowerL", "%s\\test file.shlexec", 0x0, 33},
1063  {"QuotedUpperL", "%s\\test file.shlexec", 0x0, 33},
1064 
1065  {"notaverb", "%s\\test file.shlexec", 0x10, SE_ERR_NOASSOC},
1066 
1067  {"averb", "%s\\test file.sha", 0x10, 33},
1068 
1069  /* Test file masked due to space */
1070  {NULL, "%s\\masked file.shlexec", 0x0, 33},
1071  /* Test if quoting prevents the masking */
1072  {NULL, "%s\\masked file.shlexec", 0x40, 33},
1073  /* Test with incorrect quote */
1074  {NULL, "\"%s\\masked file.shlexec", 0x0, SE_ERR_FNF},
1075 
1076  /* Test extension / URI protocol collision */
1077  {NULL, "%s\\test file.shlproto", 0x0, SE_ERR_NOASSOC},
1078 
1079  {NULL, NULL, 0}
1080 };
1081 
1083 {
1084  /* Test unquoted '%1' thingies */
1085  {"NoQuotes", "%s\\test file.shlexec", 0xa, 33},
1086  {"LowerL", "%s\\test file.shlexec", 0xa, 33},
1087  {"UpperL", "%s\\test file.shlexec", 0xa, 33},
1088 
1089  {NULL, NULL, 0}
1090 };
1091 
1092 static void test_lpFile_parsed(void)
1093 {
1094  char fileA[MAX_PATH];
1095  INT_PTR rc;
1096 
1097  if (skip_shlexec_tests)
1098  {
1099  skip("No filename parsing tests due to lack of .shlexec association\n");
1100  return;
1101  }
1102 
1103  /* existing "drawback_file.noassoc" prevents finding "drawback_file.noassoc foo.shlexec" on wine */
1104  sprintf(fileA, "%s\\drawback_file.noassoc foo.shlexec", tmpdir);
1105  rc=shell_execute(NULL, fileA, NULL, NULL);
1106  okShell(rc > 32, "failed: rc=%lu\n", rc);
1107 
1108  /* if quoted, existing "drawback_file.noassoc" not prevents finding "drawback_file.noassoc foo.shlexec" on wine */
1109  sprintf(fileA, "\"%s\\drawback_file.noassoc foo.shlexec\"", tmpdir);
1110  rc=shell_execute(NULL, fileA, NULL, NULL);
1111  okShell(rc > 32 || broken(rc == SE_ERR_FNF) /* Win95/NT4 */,
1112  "failed: rc=%lu\n", rc);
1113 
1114  /* error should be SE_ERR_FNF, not SE_ERR_NOASSOC */
1115  sprintf(fileA, "\"%s\\drawback_file.noassoc\" foo.shlexec", tmpdir);
1116  rc=shell_execute(NULL, fileA, NULL, NULL);
1117  okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
1118 
1119  /* ""command"" not works on wine (and real win9x and w2k) */
1120  sprintf(fileA, "\"\"%s\\simple.shlexec\"\"", tmpdir);
1121  rc=shell_execute(NULL, fileA, NULL, NULL);
1122  todo_wine okShell(rc > 32 || broken(rc == SE_ERR_FNF) /* Win9x/2000 */,
1123  "failed: rc=%lu\n", rc);
1124 
1125  /* nonexisting "drawback_nonexist.noassoc" not prevents finding "drawback_nonexist.noassoc foo.shlexec" on wine */
1126  sprintf(fileA, "%s\\drawback_nonexist.noassoc foo.shlexec", tmpdir);
1127  rc=shell_execute(NULL, fileA, NULL, NULL);
1128  okShell(rc > 32, "failed: rc=%lu\n", rc);
1129 
1130  /* is SEE_MASK_DOENVSUBST default flag? Should only be when XP emulates 9x (XP bug or real 95 or ME behavior ?) */
1131  rc=shell_execute(NULL, "%TMPDIR%\\simple.shlexec", NULL, NULL);
1132  todo_wine okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
1133 
1134  /* quoted */
1135  rc=shell_execute(NULL, "\"%TMPDIR%\\simple.shlexec\"", NULL, NULL);
1136  todo_wine okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
1137 
1138  /* test SEE_MASK_DOENVSUBST works */
1140  NULL, "%TMPDIR%\\simple.shlexec", NULL, NULL, NULL);
1141  okShell(rc > 32, "failed: rc=%lu\n", rc);
1142 
1143  /* quoted lpFile does not work on real win95 and nt4 */
1145  NULL, "\"%TMPDIR%\\simple.shlexec\"", NULL, NULL, NULL);
1146  okShell(rc > 32 || broken(rc == SE_ERR_FNF) /* Win95/NT4 */,
1147  "failed: rc=%lu\n", rc);
1148 }
1149 
1150 typedef struct
1151 {
1152  const char* cmd;
1153  const char* args[11];
1154  int todo;
1155 } cmdline_tests_t;
1156 
1158 {
1159  {"exe",
1160  {"exe", NULL}, 0},
1161 
1162  {"exe arg1 arg2 \"arg three\" 'four five` six\\ $even)",
1163  {"exe", "arg1", "arg2", "arg three", "'four", "five`", "six\\", "$even)", NULL}, 0},
1164 
1165  {"exe arg=1 arg-2 three\tfour\rfour\nfour ",
1166  {"exe", "arg=1", "arg-2", "three", "four\rfour\nfour", NULL}, 0},
1167 
1168  {"exe arg\"one\" \"second\"arg thirdarg ",
1169  {"exe", "argone", "secondarg", "thirdarg", NULL}, 0},
1170 
1171  /* Don't lose unclosed quoted arguments */
1172  {"exe arg1 \"unclosed",
1173  {"exe", "arg1", "unclosed", NULL}, 0},
1174 
1175  {"exe arg1 \"",
1176  {"exe", "arg1", "", NULL}, 0},
1177 
1178  /* cmd's metacharacters have no special meaning */
1179  {"exe \"one^\" \"arg\"&two three|four",
1180  {"exe", "one^", "arg&two", "three|four", NULL}, 0},
1181 
1182  /* Environment variables are not interpreted either */
1183  {"exe %TMPDIR% %2",
1184  {"exe", "%TMPDIR%", "%2", NULL}, 0},
1185 
1186  /* If not followed by a quote, backslashes go through as is */
1187  {"exe o\\ne t\\\\wo t\\\\\\ree f\\\\\\\\our ",
1188  {"exe", "o\\ne", "t\\\\wo", "t\\\\\\ree", "f\\\\\\\\our", NULL}, 0},
1189 
1190  {"exe \"o\\ne\" \"t\\\\wo\" \"t\\\\\\ree\" \"f\\\\\\\\our\" ",
1191  {"exe", "o\\ne", "t\\\\wo", "t\\\\\\ree", "f\\\\\\\\our", NULL}, 0},
1192 
1193  /* When followed by a quote their number is halved and the remainder
1194  * escapes the quote
1195  */
1196  {"exe \\\"one \\\\\"two\" \\\\\\\"three \\\\\\\\\"four\" end",
1197  {"exe", "\"one", "\\two", "\\\"three", "\\\\four", "end", NULL}, 0},
1198 
1199  {"exe \"one\\\" still\" \"two\\\\\" \"three\\\\\\\" still\" \"four\\\\\\\\\" end",
1200  {"exe", "one\" still", "two\\", "three\\\" still", "four\\\\", "end", NULL}, 0},
1201 
1202  /* One can put a quote in an unquoted string by tripling it, that is in
1203  * effect quoting it like so """ -> ". The general rule is as follows:
1204  * 3n quotes -> n quotes
1205  * 3n+1 quotes -> n quotes plus start of a quoted string
1206  * 3n+2 quotes -> n quotes (plus an empty string from the remaining pair)
1207  * Nicely, when n is 0 we get the standard rules back.
1208  */
1209  {"exe two\"\"quotes next",
1210  {"exe", "twoquotes", "next", NULL}, 0},
1211 
1212  {"exe three\"\"\"quotes next",
1213  {"exe", "three\"quotes", "next", NULL}, 0},
1214 
1215  {"exe four\"\"\"\" quotes\" next 4%3=1",
1216  {"exe", "four\" quotes", "next", "4%3=1", NULL}, 0},
1217 
1218  {"exe five\"\"\"\"\"quotes next",
1219  {"exe", "five\"quotes", "next", NULL}, 0},
1220 
1221  {"exe six\"\"\"\"\"\"quotes next",
1222  {"exe", "six\"\"quotes", "next", NULL}, 0},
1223 
1224  {"exe seven\"\"\"\"\"\"\" quotes\" next 7%3=1",
1225  {"exe", "seven\"\" quotes", "next", "7%3=1", NULL}, 0},
1226 
1227  {"exe twelve\"\"\"\"\"\"\"\"\"\"\"\"quotes next",
1228  {"exe", "twelve\"\"\"\"quotes", "next", NULL}, 0},
1229 
1230  {"exe thirteen\"\"\"\"\"\"\"\"\"\"\"\"\" quotes\" next 13%3=1",
1231  {"exe", "thirteen\"\"\"\" quotes", "next", "13%3=1", NULL}, 0},
1232 
1233  /* Inside a quoted string the opening quote is added to the set of
1234  * consecutive quotes to get the effective quotes count. This gives:
1235  * 1+3n quotes -> n quotes
1236  * 1+3n+1 quotes -> n quotes plus closes the quoted string
1237  * 1+3n+2 quotes -> n+1 quotes plus closes the quoted string
1238  */
1239  {"exe \"two\"\"quotes next",
1240  {"exe", "two\"quotes", "next", NULL}, 0},
1241 
1242  {"exe \"two\"\" next",
1243  {"exe", "two\"", "next", NULL}, 0},
1244 
1245  {"exe \"three\"\"\" quotes\" next 4%3=1",
1246  {"exe", "three\" quotes", "next", "4%3=1", NULL}, 0},
1247 
1248  {"exe \"four\"\"\"\"quotes next",
1249  {"exe", "four\"quotes", "next", NULL}, 0},
1250 
1251  {"exe \"five\"\"\"\"\"quotes next",
1252  {"exe", "five\"\"quotes", "next", NULL}, 0},
1253 
1254  {"exe \"six\"\"\"\"\"\" quotes\" next 7%3=1",
1255  {"exe", "six\"\" quotes", "next", "7%3=1", NULL}, 0},
1256 
1257  {"exe \"eleven\"\"\"\"\"\"\"\"\"\"\"quotes next",
1258  {"exe", "eleven\"\"\"\"quotes", "next", NULL}, 0},
1259 
1260  {"exe \"twelve\"\"\"\"\"\"\"\"\"\"\"\" quotes\" next 13%3=1",
1261  {"exe", "twelve\"\"\"\" quotes", "next", "13%3=1", NULL}, 0},
1262 
1263  /* Escaped consecutive quotes are fun */
1264  {"exe \"the crazy \\\\\"\"\"\\\\\" quotes",
1265  {"exe", "the crazy \\\"\\", "quotes", NULL}, 0},
1266 
1267  /* The executable path has its own rules!!!
1268  * - Backslashes have no special meaning.
1269  * - If the first character is a quote, then the second quote ends the
1270  * executable path.
1271  * - The previous rule holds even if the next character is not a space!
1272  * - If the first character is not a quote, then quotes have no special
1273  * meaning either and the executable path stops at the first space.
1274  * - The consecutive quotes rules don't apply either.
1275  * - Even if there is no space between the executable path and the first
1276  * argument, the latter is parsed using the regular rules.
1277  */
1278  {"exe\"file\"path arg1",
1279  {"exe\"file\"path", "arg1", NULL}, 0},
1280 
1281  {"exe\"file\"path\targ1",
1282  {"exe\"file\"path", "arg1", NULL}, 0},
1283 
1284  {"exe\"path\\ arg1",
1285  {"exe\"path\\", "arg1", NULL}, 0},
1286 
1287  {"\\\"exe \"arg one\"",
1288  {"\\\"exe", "arg one", NULL}, 0},
1289 
1290  {"\"spaced exe\" \"next arg\"",
1291  {"spaced exe", "next arg", NULL}, 0},
1292 
1293  {"\"spaced exe\"\t\"next arg\"",
1294  {"spaced exe", "next arg", NULL}, 0},
1295 
1296  {"\"exe\"arg\" one\" argtwo",
1297  {"exe", "arg one", "argtwo", NULL}, 0},
1298 
1299  {"\"spaced exe\\\"arg1 arg2",
1300  {"spaced exe\\", "arg1", "arg2", NULL}, 0},
1301 
1302  {"\"two\"\" arg1 ",
1303  {"two", " arg1 ", NULL}, 0},
1304 
1305  {"\"three\"\"\" arg2",
1306  {"three", "", "arg2", NULL}, 0},
1307 
1308  {"\"four\"\"\"\"arg1",
1309  {"four", "\"arg1", NULL}, 0},
1310 
1311  /* If the first character is a space then the executable path is empty */
1312  {" \"arg\"one argtwo",
1313  {"", "argone", "argtwo", NULL}, 0},
1314 
1315  {NULL, {NULL}, 0}
1316 };
1317 
1319 {
1320  WCHAR cmdW[MAX_PATH], argW[MAX_PATH];
1321  LPWSTR *cl2a;
1322  int cl2a_count;
1323  LPWSTR *argsW;
1324  int i, count;
1325 
1326  /* trace("----- cmd='%s'\n", test->cmd); */
1327  MultiByteToWideChar(CP_ACP, 0, test->cmd, -1, cmdW, ARRAY_SIZE(cmdW));
1328  argsW = cl2a = CommandLineToArgvW(cmdW, &cl2a_count);
1329  if (argsW == NULL && cl2a_count == -1)
1330  {
1331  win_skip("CommandLineToArgvW not implemented, skipping\n");
1332  return FALSE;
1333  }
1334  ok(!argsW[cl2a_count] || broken(argsW[cl2a_count] != NULL) /* before Vista */,
1335  "expected NULL-terminated list of commandline arguments\n");
1336 
1337  count = 0;
1338  while (test->args[count])
1339  count++;
1340  todo_wine_if(test->todo & 0x1)
1341  ok(cl2a_count == count, "%s: expected %d arguments, but got %d\n", test->cmd, count, cl2a_count);
1342 
1343  for (i = 0; i < cl2a_count; i++)
1344  {
1345  if (i < count)
1346  {
1347  MultiByteToWideChar(CP_ACP, 0, test->args[i], -1, argW, ARRAY_SIZE(argW));
1348  todo_wine_if(test->todo & (1 << (i+4)))
1349  ok(!lstrcmpW(*argsW, argW), "%s: arg[%d] expected %s but got %s\n", test->cmd, i, wine_dbgstr_w(argW), wine_dbgstr_w(*argsW));
1350  }
1351  else todo_wine_if(test->todo & 0x1)
1352  ok(0, "%s: got extra arg[%d]=%s\n", test->cmd, i, wine_dbgstr_w(*argsW));
1353  argsW++;
1354  }
1355  LocalFree(cl2a);
1356  return TRUE;
1357 }
1358 
1359 static void test_commandline2argv(void)
1360 {
1361  static const WCHAR exeW[] = {'e','x','e',0};
1362  const cmdline_tests_t* test;
1363  WCHAR strW[MAX_PATH];
1364  LPWSTR *args;
1365  int numargs;
1366  DWORD le;
1367 
1368  test = cmdline_tests;
1369  while (test->cmd)
1370  {
1371  if (!test_one_cmdline(test))
1372  return;
1373  test++;
1374  }
1375 
1376  SetLastError(0xdeadbeef);
1377  args = CommandLineToArgvW(exeW, NULL);
1378  le = GetLastError();
1379  ok(args == NULL && le == ERROR_INVALID_PARAMETER, "expected NULL with ERROR_INVALID_PARAMETER got %p with %u\n", args, le);
1380 
1381  SetLastError(0xdeadbeef);
1383  le = GetLastError();
1384  ok(args == NULL && le == ERROR_INVALID_PARAMETER, "expected NULL with ERROR_INVALID_PARAMETER got %p with %u\n", args, le);
1385 
1386  *strW = 0;
1387  args = CommandLineToArgvW(strW, &numargs);
1388  ok(numargs == 1 || broken(numargs > 1), "expected 1 args, got %d\n", numargs);
1389  ok(!args || (!args[numargs] || broken(args[numargs] != NULL) /* before Vista */),
1390  "expected NULL-terminated list of commandline arguments\n");
1391  if (numargs == 1)
1392  {
1394  ok(!lstrcmpW(args[0], strW), "wrong path to the current executable: %s instead of %s\n", wine_dbgstr_w(args[0]), wine_dbgstr_w(strW));
1395  }
1396  if (args) LocalFree(args);
1397 }
1398 
1399 /* The goal here is to analyze how ShellExecute() builds the command that
1400  * will be run. The tricky part is that there are three transformation
1401  * steps between the 'parameters' string we pass to ShellExecute() and the
1402  * argument list we observe in the child process:
1403  * - The parsing of 'parameters' string into individual arguments. The tests
1404  * show this is done differently from both CreateProcess() and
1405  * CommandLineToArgv()!
1406  * - The way the command 'formatting directives' such as %1, %2, etc are
1407  * handled.
1408  * - And the way the resulting command line is then parsed to yield the
1409  * argument list we check.
1410  */
1411 typedef struct
1412 {
1413  const char* verb;
1414  const char* params;
1415  int todo;
1416  const char *cmd;
1417  const char *broken;
1418 } argify_tests_t;
1419 
1421 {
1422  /* Start with three simple parameters. Notice that one can reorder and
1423  * duplicate the parameters. Also notice how %* take the raw input
1424  * parameters string, including the trailing spaces, no matter what
1425  * arguments have already been used.
1426  */
1427  {"Params232S", "p2 p3 p4 ", TRUE,
1428  " p2 p3 \"p2\" \"p2 p3 p4 \""},
1429 
1430  /* Unquoted argument references like %2 don't automatically quote their
1431  * argument. Similarly, when they are quoted they don't escape the quotes
1432  * that their argument may contain.
1433  */
1434  {"Params232S", "\"p two\" p3 p4 ", TRUE,
1435  " p two p3 \"p two\" \"\"p two\" p3 p4 \""},
1436 
1437  /* Only single digits are supported so only %1 to %9. Shown here with %20
1438  * because %10 is a pain.
1439  */
1440  {"Params20", "p", FALSE,
1441  " \"p0\""},
1442 
1443  /* Only (double-)quotes have a special meaning. */
1444  {"Params23456", "'p2 p3` p4\\ $even", FALSE,
1445  " \"'p2\" \"p3`\" \"p4\\\" \"$even\" \"\""},
1446 
1447  {"Params23456", "p=2 p-3 p4\tp4\rp4\np4", TRUE,
1448  " \"p=2\" \"p-3\" \"p4\tp4\rp4\np4\" \"\" \"\""},
1449 
1450  /* In unquoted strings, quotes are treated are a parameter separator just
1451  * like spaces! However they can be doubled to get a literal quote.
1452  * Specifically:
1453  * 2n quotes -> n quotes
1454  * 2n+1 quotes -> n quotes and a parameter separator
1455  */
1456  {"Params23456789", "one\"quote \"p four\" one\"quote p7", TRUE,
1457  " \"one\" \"quote\" \"p four\" \"one\" \"quote\" \"p7\" \"\" \"\""},
1458 
1459  {"Params23456789", "two\"\"quotes \"p three\" two\"\"quotes p5", TRUE,
1460  " \"two\"quotes\" \"p three\" \"two\"quotes\" \"p5\" \"\" \"\" \"\" \"\""},
1461 
1462  {"Params23456789", "three\"\"\"quotes \"p four\" three\"\"\"quotes p6", TRUE,
1463  " \"three\"\" \"quotes\" \"p four\" \"three\"\" \"quotes\" \"p6\" \"\" \"\""},
1464 
1465  {"Params23456789", "four\"\"\"\"quotes \"p three\" four\"\"\"\"quotes p5", TRUE,
1466  " \"four\"\"quotes\" \"p three\" \"four\"\"quotes\" \"p5\" \"\" \"\" \"\" \"\""},
1467 
1468  /* Quoted strings cannot be continued by tacking on a non space character
1469  * either.
1470  */
1471  {"Params23456", "\"p two\"p3 \"p four\"p5 p6", TRUE,
1472  " \"p two\" \"p3\" \"p four\" \"p5\" \"p6\""},
1473 
1474  /* In quoted strings, the quotes are halved and an odd number closes the
1475  * string. Specifically:
1476  * 2n quotes -> n quotes
1477  * 2n+1 quotes -> n quotes and closes the string and hence the parameter
1478  */
1479  {"Params23456789", "\"one q\"uote \"p four\" \"one q\"uote p7", TRUE,
1480  " \"one q\" \"uote\" \"p four\" \"one q\" \"uote\" \"p7\" \"\" \"\""},
1481 
1482  {"Params23456789", "\"two \"\" quotes\" \"p three\" \"two \"\" quotes\" p5", TRUE,
1483  " \"two \" quotes\" \"p three\" \"two \" quotes\" \"p5\" \"\" \"\" \"\" \"\""},
1484 
1485  {"Params23456789", "\"three q\"\"\"uotes \"p four\" \"three q\"\"\"uotes p7", TRUE,
1486  " \"three q\"\" \"uotes\" \"p four\" \"three q\"\" \"uotes\" \"p7\" \"\" \"\""},
1487 
1488  {"Params23456789", "\"four \"\"\"\" quotes\" \"p three\" \"four \"\"\"\" quotes\" p5", TRUE,
1489  " \"four \"\" quotes\" \"p three\" \"four \"\" quotes\" \"p5\" \"\" \"\" \"\" \"\""},
1490 
1491  /* The quoted string rules also apply to consecutive quotes at the start
1492  * of a parameter but don't count the opening quote!
1493  */
1494  {"Params23456789", "\"\"twoquotes \"p four\" \"\"twoquotes p7", TRUE,
1495  " \"\" \"twoquotes\" \"p four\" \"\" \"twoquotes\" \"p7\" \"\" \"\""},
1496 
1497  {"Params23456789", "\"\"\"three quotes\" \"p three\" \"\"\"three quotes\" p5", TRUE,
1498  " \"\"three quotes\" \"p three\" \"\"three quotes\" \"p5\" \"\" \"\" \"\" \"\""},
1499 
1500  {"Params23456789", "\"\"\"\"fourquotes \"p four\" \"\"\"\"fourquotes p7", TRUE,
1501  " \"\"\" \"fourquotes\" \"p four\" \"\"\" \"fourquotes\" \"p7\" \"\" \"\""},
1502 
1503  /* An unclosed quoted string gets lost! */
1504  {"Params23456", "p2 \"p3\" \"p4 is lost", TRUE,
1505  " \"p2\" \"p3\" \"\" \"\" \"\"",
1506  " \"p2\" \"p3\" \"p3\" \"\" \"\""}, /* NT4/2k */
1507 
1508  /* Backslashes have no special meaning even when preceding quotes. All
1509  * they do is start an unquoted string.
1510  */
1511  {"Params23456", "\\\"p\\three \"pfour\\\" pfive", TRUE,
1512  " \"\\\" \"p\\three\" \"pfour\\\" \"pfive\" \"\""},
1513 
1514  /* Environment variables are left untouched. */
1515  {"Params23456", "%TMPDIR% %t %c", FALSE,
1516  " \"%TMPDIR%\" \"%t\" \"%c\" \"\" \"\""},
1517 
1518  /* %~2 is equivalent to %*. However %~3 and higher include the spaces
1519  * before the parameter!
1520  * (but not the previous parameter's closing quote fortunately)
1521  */
1522  {"Params2345Etc", "p2 p3 \"p4\" p5 p6 ", TRUE,
1523  " ~2=\"p2 p3 \"p4\" p5 p6 \" ~3=\" p3 \"p4\" p5 p6 \" ~4=\" \"p4\" p5 p6 \" ~5= p5 p6 "},
1524 
1525  /* %~n works even if there is no nth parameter. */
1526  {"Params9Etc", "p2 p3 p4 p5 p6 p7 p8 ", TRUE,
1527  " ~9=\" \""},
1528 
1529  {"Params9Etc", "p2 p3 p4 p5 p6 p7 ", TRUE,
1530  " ~9=\"\""},
1531 
1532  /* The %~n directives also transmit the tenth parameter and beyond. */
1533  {"Params9Etc", "p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 and beyond!", TRUE,
1534  " ~9=\" p9 p10 p11 and beyond!\""},
1535 
1536  /* Bad formatting directives lose their % sign, except those followed by
1537  * a tilde! Environment variables are not expanded but lose their % sign.
1538  */
1539  {"ParamsBad", "p2 p3 p4 p5", TRUE,
1540  " \"% - %~ %~0 %~1 %~a %~* a b c TMPDIR\""},
1541 
1542  {0}
1543 };
1544 
1545 static void test_argify(void)
1546 {
1547  char fileA[MAX_PATH], params[2*MAX_PATH+12];
1548  INT_PTR rc;
1549  const argify_tests_t* test;
1550  const char *bad;
1551  const char* cmd;
1552 
1553  /* Test with a long parameter */
1554  for (rc = 0; rc < MAX_PATH; rc++)
1555  fileA[rc] = 'a' + rc % 26;
1556  fileA[MAX_PATH-1] = '\0';
1557  sprintf(params, "shlexec \"%s\" %s", child_file, fileA);
1558 
1559  /* We need NOZONECHECKS on Win2003 to block a dialog */
1561  okShell(rc > 32, "failed: rc=%lu\n", rc);
1562  okChildInt("argcA", 4);
1563  okChildPath("argvA3", fileA);
1564 
1565  if (skip_shlexec_tests)
1566  {
1567  skip("No argify tests due to lack of .shlexec association\n");
1568  return;
1569  }
1570 
1571  create_test_verb("shlexec.shlexec", "Params232S", 0, "Params232S %2 %3 \"%2\" \"%*\"");
1572  create_test_verb("shlexec.shlexec", "Params23456", 0, "Params23456 \"%2\" \"%3\" \"%4\" \"%5\" \"%6\"");
1573  create_test_verb("shlexec.shlexec", "Params23456789", 0, "Params23456789 \"%2\" \"%3\" \"%4\" \"%5\" \"%6\" \"%7\" \"%8\" \"%9\"");
1574  create_test_verb("shlexec.shlexec", "Params2345Etc", 0, "Params2345Etc ~2=\"%~2\" ~3=\"%~3\" ~4=\"%~4\" ~5=%~5");
1575  create_test_verb("shlexec.shlexec", "Params9Etc", 0, "Params9Etc ~9=\"%~9\"");
1576  create_test_verb("shlexec.shlexec", "Params20", 0, "Params20 \"%20\"");
1577  create_test_verb("shlexec.shlexec", "ParamsBad", 0, "ParamsBad \"%% %- %~ %~0 %~1 %~a %~* %a %b %c %TMPDIR%\"");
1578 
1579  sprintf(fileA, "%s\\test file.shlexec", tmpdir);
1580 
1581  test = argify_tests;
1582  while (test->params)
1583  {
1584  bad = test->broken ? test->broken : test->cmd;
1585 
1586  rc = shell_execute_ex(SEE_MASK_DOENVSUBST, test->verb, fileA, test->params, NULL, NULL);
1587  okShell(rc > 32, "failed: rc=%lu\n", rc);
1588 
1589  cmd = getChildString("Child", "cmdlineA");
1590  /* Our commands are such that the verb immediately precedes the
1591  * part we are interested in.
1592  */
1593  if (cmd) cmd = strstr(cmd, test->verb);
1594  if (cmd) cmd += strlen(test->verb);
1595  if (!cmd) cmd = "(null)";
1596  todo_wine_if(test->todo)
1597  okShell(!strcmp(cmd, test->cmd) || broken(!strcmp(cmd, bad)),
1598  "expected '%s', got '%s'\n", cmd, test->cmd);
1599  test++;
1600  }
1601 }
1602 
1603 static void test_filename(void)
1604 {
1605  char filename[MAX_PATH];
1606  const filename_tests_t* test;
1607  char* c;
1608  INT_PTR rc;
1609 
1610  if (skip_shlexec_tests)
1611  {
1612  skip("No ShellExecute/filename tests due to lack of .shlexec association\n");
1613  return;
1614  }
1615 
1617  while (test->basename)
1618  {
1619  BOOL quotedfile = FALSE;
1620 
1621  if (skip_noassoc_tests && test->rc == SE_ERR_NOASSOC)
1622  {
1623  win_skip("Skipping shellexecute of file with unassociated extension\n");
1624  test++;
1625  continue;
1626  }
1627 
1628  sprintf(filename, test->basename, tmpdir);
1629  if (strchr(filename, '/'))
1630  {
1631  c=filename;
1632  while (*c)
1633  {
1634  if (*c=='\\')
1635  *c='/';
1636  c++;
1637  }
1638  }
1639  if ((test->todo & 0x40)==0)
1640  {
1641  rc=shell_execute(test->verb, filename, NULL, NULL);
1642  }
1643  else
1644  {
1645  char quoted[MAX_PATH + 2];
1646 
1647  quotedfile = TRUE;
1648  sprintf(quoted, "\"%s\"", filename);
1649  rc=shell_execute(test->verb, quoted, NULL, NULL);
1650  }
1651  if (rc > 32)
1652  rc=33;
1653  okShell(rc==test->rc ||
1654  broken(quotedfile && rc == SE_ERR_FNF), /* NT4 */
1655  "failed: rc=%ld err=%u\n", rc, GetLastError());
1656  if (rc == 33)
1657  {
1658  const char* verb;
1659  todo_wine_if(test->todo & 0x2)
1660  okChildInt("argcA", 5);
1661  verb=(test->verb ? test->verb : "Open");
1662  todo_wine_if(test->todo & 0x4)
1663  okChildString("argvA3", verb);
1664  todo_wine_if(test->todo & 0x8)
1665  okChildPath("argvA4", filename);
1666  }
1667  test++;
1668  }
1669 
1671  while (test->basename)
1672  {
1673  sprintf(filename, test->basename, tmpdir);
1674  rc=shell_execute(test->verb, filename, NULL, NULL);
1675  if (rc > 32)
1676  rc=33;
1677  todo_wine_if(test->todo & 0x1)
1678  okShell(rc==test->rc, "failed: rc=%ld err=%u\n", rc, GetLastError());
1679  if (rc==0)
1680  {
1681  int count;
1682  const char* verb;
1683  char* str;
1684 
1685  verb=(test->verb ? test->verb : "Open");
1686  todo_wine_if(test->todo & 0x4)
1687  okChildString("argvA3", verb);
1688 
1689  count=4;
1690  str=filename;
1691  while (1)
1692  {
1693  char attrib[18];
1694  char* space;
1695  space=strchr(str, ' ');
1696  if (space)
1697  *space='\0';
1698  sprintf(attrib, "argvA%d", count);
1699  todo_wine_if(test->todo & 0x8)
1700  okChildPath(attrib, str);
1701  count++;
1702  if (!space)
1703  break;
1704  str=space+1;
1705  }
1706  todo_wine_if(test->todo & 0x2)
1707  okChildInt("argcA", count);
1708  }
1709  test++;
1710  }
1711 
1712  if (dllver.dwMajorVersion != 0)
1713  {
1714  /* The more recent versions of shell32.dll accept quoted filenames
1715  * while older ones (e.g. 4.00) don't. Still we want to test this
1716  * because IE 6 depends on the new behavior.
1717  * One day we may need to check the exact version of the dll but for
1718  * now making sure DllGetVersion() is present is sufficient.
1719  */
1720  sprintf(filename, "\"%s\\test file.shlexec\"", tmpdir);
1722  okShell(rc > 32, "failed: rc=%ld err=%u\n", rc, GetLastError());
1723  okChildInt("argcA", 5);
1724  okChildString("argvA3", "Open");
1725  sprintf(filename, "%s\\test file.shlexec", tmpdir);
1726  okChildPath("argvA4", filename);
1727  }
1728 
1729  sprintf(filename, "\"%s\\test file.sha\"", tmpdir);
1731  todo_wine okShell(rc > 32, "failed: rc=%ld err=%u\n", rc, GetLastError());
1732  okChildInt("argcA", 5);
1733  todo_wine okChildString("argvA3", "averb");
1734  sprintf(filename, "%s\\test file.sha", tmpdir);
1735  todo_wine okChildPath("argvA4", filename);
1736 }
1737 
1738 typedef struct
1739 {
1740  const char* urlprefix;
1741  const char* basename;
1742  int flags;
1743  int todo;
1744 } fileurl_tests_t;
1745 
1746 #define URL_SUCCESS 0x1
1747 #define USE_COLON 0x2
1748 #define USE_BSLASH 0x4
1749 
1751 {
1752  /* How many slashes does it take... */
1753  {"file:", "%s\\test file.shlexec", URL_SUCCESS, 0},
1754  {"file:/", "%s\\test file.shlexec", URL_SUCCESS, 0},
1755  {"file://", "%s\\test file.shlexec", URL_SUCCESS, 0},
1756  {"file:///", "%s\\test file.shlexec", URL_SUCCESS, 0},
1757  {"File:///", "%s\\test file.shlexec", URL_SUCCESS, 0},
1758  {"file:////", "%s\\test file.shlexec", URL_SUCCESS, 0},
1759  {"file://///", "%s\\test file.shlexec", 0, 0},
1760 
1761  /* Test with Windows-style paths */
1762  {"file:///", "%s\\test file.shlexec", URL_SUCCESS | USE_COLON, 0},
1763  {"file:///", "%s\\test file.shlexec", URL_SUCCESS | USE_BSLASH, 0},
1764 
1765  /* Check handling of hostnames */
1766  {"file://localhost/", "%s\\test file.shlexec", URL_SUCCESS, 0},
1767  {"file://localhost:80/", "%s\\test file.shlexec", 0, 0},
1768  {"file://LocalHost/", "%s\\test file.shlexec", URL_SUCCESS, 0},
1769  {"file://127.0.0.1/", "%s\\test file.shlexec", 0, 0},
1770  {"file://::1/", "%s\\test file.shlexec", 0, 0},
1771  {"file://notahost/", "%s\\test file.shlexec", 0, 0},
1772 
1773  /* Environment variables are not expanded in URLs */
1774  {"%urlprefix%", "%s\\test file.shlexec", 0, 0x1},
1775  {"file:///", "%%TMPDIR%%\\test file.shlexec", 0, 0},
1776 
1777  /* Test shortcuts vs. URLs */
1778  {"file://///", "%s\\test_shortcut_shlexec.lnk", 0, 0x1c},
1779 
1780  /* Confuse things by mixing protocols */
1781  {"file://", "shlproto://foo/bar", USE_COLON, 0},
1782 
1783  {NULL, NULL, 0, 0}
1784 };
1785 
1786 static void test_fileurls(void)
1787 {
1788  char filename[MAX_PATH], fileurl[MAX_PATH], longtmpdir[MAX_PATH];
1789  char command[MAX_PATH];
1790  const fileurl_tests_t* test;
1791  char *s;
1792  INT_PTR rc;
1793 
1794  if (skip_shlexec_tests)
1795  {
1796  skip("No file URL tests due to lack of .shlexec association\n");
1797  return;
1798  }
1799 
1801  "file:///nosuchfile.shlexec", NULL, NULL, NULL);
1802  if (rc > 32)
1803  {
1804  win_skip("shell32 is too old (likely < 4.72). Skipping the file URL tests\n");
1805  return;
1806  }
1807 
1808  get_long_path_name(tmpdir, longtmpdir, ARRAY_SIZE(longtmpdir));
1809  SetEnvironmentVariableA("urlprefix", "file:///");
1810 
1812  while (test->basename)
1813  {
1814  /* Build the file URL */
1815  sprintf(filename, test->basename, longtmpdir);
1816  strcpy(fileurl, test->urlprefix);
1817  strcat(fileurl, filename);
1818  s = fileurl + strlen(test->urlprefix);
1819  while (*s)
1820  {
1821  if (!(test->flags & USE_COLON) && *s == ':')
1822  *s = '|';
1823  else if (!(test->flags & USE_BSLASH) && *s == '\\')
1824  *s = '/';
1825  s++;
1826  }
1827 
1828  /* Test it first with FindExecutable() */
1829  rc = (INT_PTR)FindExecutableA(fileurl, NULL, command);
1830  ok(rc == SE_ERR_FNF, "FindExecutable(%s) failed: bad rc=%lu\n", fileurl, rc);
1831 
1832  /* Then ShellExecute() */
1833  if ((test->todo & 0x10) == 0)
1834  rc = shell_execute(NULL, fileurl, NULL, NULL);
1835  else todo_wait
1836  rc = shell_execute(NULL, fileurl, NULL, NULL);
1837  if (bad_shellexecute)
1838  {
1839  win_skip("shell32 is too old (likely 4.72). Skipping the file URL tests\n");
1840  break;
1841  }
1842  if (test->flags & URL_SUCCESS)
1843  {
1844  todo_wine_if(test->todo & 0x1)
1845  okShell(rc > 32, "failed: bad rc=%lu\n", rc);
1846  }
1847  else
1848  {
1849  todo_wine_if(test->todo & 0x1)
1850  okShell(rc == SE_ERR_FNF || rc == SE_ERR_PNF ||
1851  broken(rc == SE_ERR_ACCESSDENIED) /* win2000 */,
1852  "failed: bad rc=%lu\n", rc);
1853  }
1854  if (rc == 33)
1855  {
1856  todo_wine_if(test->todo & 0x2)
1857  okChildInt("argcA", 5);
1858  todo_wine_if(test->todo & 0x4)
1859  okChildString("argvA3", "Open");
1860  todo_wine_if(test->todo & 0x8)
1861  okChildPath("argvA4", filename);
1862  }
1863  test++;
1864  }
1865 
1866  SetEnvironmentVariableA("urlprefix", NULL);
1867 }
1868 
1869 static void test_urls(void)
1870 {
1871  char url[MAX_PATH];
1872  INT_PTR rc;
1873 
1874  if (!create_test_class("fakeproto", FALSE))
1875  {
1876  skip("Unable to create 'fakeproto' class for URL tests\n");
1877  return;
1878  }
1879  create_test_verb("fakeproto", "open", 0, "URL %1");
1880 
1881  create_test_class("shlpaverb", TRUE);
1882  create_test_verb("shlpaverb", "averb", 0, "PAVerb \"%1\"");
1883 
1884  /* Protocols must be properly declared */
1885  rc = shell_execute(NULL, "notaproto://foo", NULL, NULL);
1886  ok(rc == SE_ERR_NOASSOC || broken(rc == SE_ERR_ACCESSDENIED),
1887  "%s returned %lu\n", shell_call, rc);
1888 
1889  rc = shell_execute(NULL, "fakeproto://foo/bar", NULL, NULL);
1891  "%s returned %lu\n", shell_call, rc);
1892 
1893  /* Here's a real live one */
1894  rc = shell_execute(NULL, "shlproto://foo/bar", NULL, NULL);
1895  ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc);
1896  okChildInt("argcA", 5);
1897  okChildString("argvA3", "URL");
1898  okChildString("argvA4", "shlproto://foo/bar");
1899 
1900  /* Check default verb detection */
1901  rc = shell_execute(NULL, "shlpaverb://foo/bar", NULL, NULL);
1902  todo_wine ok(rc > 32 || /* XP+IE7 - Win10 */
1903  broken(rc == SE_ERR_NOASSOC), /* XP+IE6 */
1904  "%s failed: rc=%lu\n", shell_call, rc);
1905  if (rc > 32)
1906  {
1907  okChildInt("argcA", 5);
1908  todo_wine okChildString("argvA3", "PAVerb");
1909  todo_wine okChildString("argvA4", "shlpaverb://foo/bar");
1910  }
1911 
1912  /* But alternative verbs are a recent feature! */
1913  rc = shell_execute("averb", "shlproto://foo/bar", NULL, NULL);
1914  ok(rc > 32 || /* Win8 - Win10 */
1915  broken(rc == SE_ERR_ACCESSDENIED), /* XP - Win7 */
1916  "%s failed: rc=%lu\n", shell_call, rc);
1917  if (rc > 32)
1918  {
1919  okChildString("argvA3", "AVerb");
1920  okChildString("argvA4", "shlproto://foo/bar");
1921  }
1922 
1923  /* A .lnk ending does not turn a URL into a shortcut */
1924  rc = shell_execute(NULL, "shlproto://foo/bar.lnk", NULL, NULL);
1925  ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc);
1926  okChildInt("argcA", 5);
1927  okChildString("argvA3", "URL");
1928  okChildString("argvA4", "shlproto://foo/bar.lnk");
1929 
1930  /* Neither does a .exe extension */
1931  rc = shell_execute(NULL, "shlproto://foo/bar.exe", NULL, NULL);
1932  ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc);
1933  okChildInt("argcA", 5);
1934  okChildString("argvA3", "URL");
1935  okChildString("argvA4", "shlproto://foo/bar.exe");
1936 
1937  /* But a class name overrides it */
1938  rc = shell_execute(NULL, "shlproto://foo/bar", "shlexec.shlexec", NULL);
1939  ok(rc > 32, "%s failed: rc=%lu\n", shell_call, rc);
1940  okChildInt("argcA", 5);
1941  okChildString("argvA3", "URL");
1942  okChildString("argvA4", "shlproto://foo/bar");
1943 
1944  /* Environment variables are expanded in URLs (but not in file URLs!) */
1946  NULL, "shlproto://%TMPDIR%/bar", NULL, NULL, NULL);
1947  okShell(rc > 32, "failed: rc=%lu\n", rc);
1948  okChildInt("argcA", 5);
1949  sprintf(url, "shlproto://%s/bar", tmpdir);
1950  okChildString("argvA3", "URL");
1951  okChildStringBroken("argvA4", url, "shlproto://%TMPDIR%/bar");
1952 
1953  /* But only after the path has been identified as a URL */
1954  SetEnvironmentVariableA("urlprefix", "shlproto:///");
1955  rc = shell_execute(NULL, "%urlprefix%foo", NULL, NULL);
1956  todo_wine ok(rc == SE_ERR_FNF, "%s returned %lu\n", shell_call, rc);
1957  SetEnvironmentVariableA("urlprefix", NULL);
1958 
1959  delete_test_class("fakeproto");
1960  delete_test_class("shlpaverb");
1961 }
1962 
1963 static void test_find_executable(void)
1964 {
1965  char notepad_path[MAX_PATH];
1966  char filename[MAX_PATH];
1967  char command[MAX_PATH];
1968  const filename_tests_t* test;
1969  INT_PTR rc;
1970 
1971  if (!create_test_association(".sfe"))
1972  {
1973  skip("Unable to create association for '.sfe'\n");
1974  return;
1975  }
1976  create_test_verb("shlexec.sfe", "Open", 1, "%1");
1977 
1978  /* Don't test FindExecutable(..., NULL), it always crashes */
1979 
1980  strcpy(command, "your word");
1981  if (0) /* Can crash on Vista! */
1982  {
1984  ok(rc == SE_ERR_FNF || rc > 32 /* nt4 */, "FindExecutable(NULL) returned %ld\n", rc);
1985  ok(strcmp(command, "your word") != 0, "FindExecutable(NULL) returned command=[%s]\n", command);
1986  }
1987 
1988  GetSystemDirectoryA( notepad_path, MAX_PATH );
1989  strcat( notepad_path, "\\notepad.exe" );
1990 
1991  /* Search for something that should be in the system-wide search path (no default directory) */
1992  strcpy(command, "your word");
1993  rc=(INT_PTR)FindExecutableA("notepad.exe", NULL, command);
1994  ok(rc > 32, "FindExecutable(%s) returned %ld\n", "notepad.exe", rc);
1995  ok(strcasecmp(command, notepad_path) == 0, "FindExecutable(%s) returned command=[%s]\n", "notepad.exe", command);
1996 
1997  /* Search for something that should be in the system-wide search path (with default directory) */
1998  strcpy(command, "your word");
1999  rc=(INT_PTR)FindExecutableA("notepad.exe", tmpdir, command);
2000  ok(rc > 32, "FindExecutable(%s) returned %ld\n", "notepad.exe", rc);
2001  ok(strcasecmp(command, notepad_path) == 0, "FindExecutable(%s) returned command=[%s]\n", "notepad.exe", command);
2002 
2003  strcpy(command, "your word");
2005  ok(rc == SE_ERR_NOASSOC /* >= win2000 */ || rc > 32 /* win98, nt4 */, "FindExecutable(NULL) returned %ld\n", rc);
2006  ok(strcmp(command, "your word") != 0, "FindExecutable(NULL) returned command=[%s]\n", command);
2007 
2008  sprintf(filename, "%s\\test file.sfe", tmpdir);
2010  ok(rc > 32, "FindExecutable(%s) returned %ld\n", filename, rc);
2011  /* Depending on the platform, command could be '%1' or 'test file.sfe' */
2012 
2013  rc=(INT_PTR)FindExecutableA("test file.sfe", tmpdir, command);
2014  ok(rc > 32, "FindExecutable(%s) returned %ld\n", filename, rc);
2015 
2016  rc=(INT_PTR)FindExecutableA("test file.sfe", NULL, command);
2017  ok(rc == SE_ERR_FNF, "FindExecutable(%s) returned %ld\n", filename, rc);
2018 
2019  delete_test_association(".sfe");
2020 
2021  if (!create_test_association(".shl"))
2022  {
2023  skip("Unable to create association for '.shl'\n");
2024  return;
2025  }
2026  create_test_verb("shlexec.shl", "Open", 0, "Open");
2027 
2028  sprintf(filename, "%s\\test file.shl", tmpdir);
2030  ok(rc == SE_ERR_FNF /* NT4 */ || rc > 32, "FindExecutable(%s) returned %ld\n", filename, rc);
2031 
2032  sprintf(filename, "%s\\test file.shlfoo", tmpdir);
2034 
2035  delete_test_association(".shl");
2036 
2037  if (rc > 32)
2038  {
2039  /* On Windows XP and 2003 FindExecutable() is completely broken.
2040  * Probably what it does is convert the filename to 8.3 format,
2041  * which as a side effect converts the '.shlfoo' extension to '.shl',
2042  * and then tries to find an association for '.shl'. This means it
2043  * will normally fail on most extensions with more than 3 characters,
2044  * like '.mpeg', etc.
2045  * Also it means we cannot do any other test.
2046  */
2047  win_skip("FindExecutable() is broken -> not running 4+ character extension tests\n");
2048  return;
2049  }
2050 
2051  if (skip_shlexec_tests)
2052  {
2053  skip("No FindExecutable/filename tests due to lack of .shlexec association\n");
2054  return;
2055  }
2056 
2058  while (test->basename)
2059  {
2060  sprintf(filename, test->basename, tmpdir);
2061  if (strchr(filename, '/'))
2062  {
2063  char* c;
2064  c=filename;
2065  while (*c)
2066  {
2067  if (*c=='\\')
2068  *c='/';
2069  c++;
2070  }
2071  }
2072  /* Win98 does not '\0'-terminate command! */
2073  memset(command, '\0', sizeof(command));
2075  if (rc > 32)
2076  rc=33;
2077  todo_wine_if(test->todo & 0x10)
2078  ok(rc==test->rc, "FindExecutable(%s) failed: rc=%ld\n", filename, rc);
2079  if (rc > 32)
2080  {
2081  BOOL equal;
2082  equal=strcmp(command, argv0) == 0 ||
2083  /* NT4 returns an extra 0x8 character! */
2084  (strlen(command) == strlen(argv0)+1 && strncmp(command, argv0, strlen(argv0)) == 0);
2085  todo_wine_if(test->todo & 0x20)
2086  ok(equal, "FindExecutable(%s) returned command='%s' instead of '%s'\n",
2087  filename, command, argv0);
2088  }
2089  test++;
2090  }
2091 }
2092 
2093 
2095 {
2096  /* Pass bad / nonexistent filenames as a parameter */
2097  {NULL, "%s\\nonexistent.shlexec", 0xa, 33},
2098  {NULL, "%s\\nonexistent.noassoc", 0xa, 33},
2099 
2100  /* Pass regular paths as a parameter */
2101  {NULL, "%s\\test file.shlexec", 0xa, 33},
2102  {NULL, "%s/%%nasty%% $file.shlexec", 0xa, 33},
2103 
2104  /* Pass filenames with no association as a parameter */
2105  {NULL, "%s\\test file.noassoc", 0xa, 33},
2106 
2107  {NULL, NULL, 0}
2108 };
2109 
2110 static void test_lnks(void)
2111 {
2112  char filename[MAX_PATH];
2113  char params[MAX_PATH];
2114  const filename_tests_t* test;
2115  INT_PTR rc;
2116 
2117  if (skip_shlexec_tests)
2118  skip("No FindExecutable/filename tests due to lack of .shlexec association\n");
2119  else
2120  {
2121  /* Should open through our association */
2122  sprintf(filename, "%s\\test_shortcut_shlexec.lnk", tmpdir);
2124  okShell(rc > 32, "failed: rc=%lu err=%u\n", rc, GetLastError());
2125  okChildInt("argcA", 5);
2126  okChildString("argvA3", "Open");
2127  sprintf(params, "%s\\test file.shlexec", tmpdir);
2129  okChildPath("argvA4", filename);
2130 
2131  rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_DOENVSUBST, NULL, "%TMPDIR%\\test_shortcut_shlexec.lnk", NULL, NULL, NULL);
2132  okShell(rc > 32, "failed: rc=%lu err=%u\n", rc, GetLastError());
2133  okChildInt("argcA", 5);
2134  okChildString("argvA3", "Open");
2135  sprintf(params, "%s\\test file.shlexec", tmpdir);
2137  okChildPath("argvA4", filename);
2138  }
2139 
2140  /* Should just run our executable */
2141  sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir);
2143  okShell(rc > 32, "failed: rc=%lu err=%u\n", rc, GetLastError());
2144  okChildInt("argcA", 4);
2145  okChildString("argvA3", "Lnk");
2146 
2147  if (!skip_shlexec_tests)
2148  {
2149  /* An explicit class overrides lnk's ContextMenuHandler */
2151  okShell(rc > 32, "failed: rc=%lu err=%u\n", rc, GetLastError());
2152  okChildInt("argcA", 5);
2153  okChildString("argvA3", "Open");
2154  okChildPath("argvA4", filename);
2155  }
2156 
2157  if (dllver.dwMajorVersion>=6)
2158  {
2159  char* c;
2160  /* Recent versions of shell32.dll accept '/'s in shortcut paths.
2161  * Older versions don't or are quite buggy in this regard.
2162  */
2163  sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir);
2164  c=filename;
2165  while (*c)
2166  {
2167  if (*c=='\\')
2168  *c='/';
2169  c++;
2170  }
2172  okShell(rc > 32, "failed: rc=%lu err=%u\n", rc, GetLastError());
2173  okChildInt("argcA", 4);
2174  okChildString("argvA3", "Lnk");
2175  }
2176 
2177  sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir);
2178  test=lnk_tests;
2179  while (test->basename)
2180  {
2181  params[0]='\"';
2182  sprintf(params+1, test->basename, tmpdir);
2183  strcat(params,"\"");
2185  NULL, NULL);
2186  if (rc > 32)
2187  rc=33;
2188  todo_wine_if(test->todo & 0x1)
2189  okShell(rc==test->rc, "failed: rc=%lu err=%u\n", rc, GetLastError());
2190  if (rc==0)
2191  {
2192  todo_wine_if(test->todo & 0x2)
2193  okChildInt("argcA", 5);
2194  todo_wine_if(test->todo & 0x4)
2195  okChildString("argvA3", "Lnk");
2196  sprintf(params, test->basename, tmpdir);
2197  okChildPath("argvA4", params);
2198  }
2199  test++;
2200  }
2201 }
2202 
2203 
2204 static void test_exes(void)
2205 {
2206  char filename[MAX_PATH];
2207  char params[1024];
2208  INT_PTR rc;
2209 
2210  sprintf(params, "shlexec \"%s\" Exec", child_file);
2211 
2212  /* We need NOZONECHECKS on Win2003 to block a dialog */
2214  NULL, NULL);
2215  okShell(rc > 32, "returned %lu\n", rc);
2216  okChildInt("argcA", 4);
2217  okChildString("argvA3", "Exec");
2218 
2219  if (! skip_noassoc_tests)
2220  {
2221  sprintf(filename, "%s\\test file.noassoc", tmpdir);
2222  if (CopyFileA(argv0, filename, FALSE))
2223  {
2225  todo_wine {
2226  okShell(rc==SE_ERR_NOASSOC, "returned %lu\n", rc);
2227  }
2228  }
2229  }
2230  else
2231  {
2232  win_skip("Skipping shellexecute of file with unassociated extension\n");
2233  }
2234 
2235  /* test combining executable and parameters */
2236  sprintf(filename, "%s shlexec \"%s\" Exec", argv0, child_file);
2237  rc = shell_execute(NULL, filename, NULL, NULL);
2238  okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
2239 
2240  sprintf(filename, "\"%s\" shlexec \"%s\" Exec", argv0, child_file);
2241  rc = shell_execute(NULL, filename, NULL, NULL);
2242  okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
2243 
2244  /* A verb, even if invalid, overrides the normal handling of executables */
2246  "notaverb", argv0, NULL, NULL, NULL);
2247  todo_wine okShell(rc == SE_ERR_NOASSOC, "returned %lu\n", rc);
2248 
2249  if (!skip_shlexec_tests)
2250  {
2251  /* A class overrides the normal handling of executables too */
2252  /* FIXME SEE_MASK_FLAG_NO_UI is only needed due to Wine's bug */
2254  NULL, argv0, NULL, NULL, ".shlexec");
2255  todo_wine okShell(rc > 32, "returned %lu\n", rc);
2256  okChildInt("argcA", 5);
2257  todo_wine okChildString("argvA3", "Open");
2258  todo_wine okChildPath("argvA4", argv0);
2259  }
2260 }
2261 
2262 typedef struct
2263 {
2264  const char* command;
2265  const char* ddeexec;
2266  const char* application;
2267  const char* topic;
2268  const char* ifexec;
2270  const char* expectedDdeExec;
2272 } dde_tests_t;
2273 
2275 {
2276  /* Test passing and not passing command-line
2277  * argument, no DDE */
2278  {"", NULL, NULL, NULL, NULL, 0, ""},
2279  {"\"%1\"", NULL, NULL, NULL, NULL, 1, ""},
2280 
2281  /* Test passing and not passing command-line
2282  * argument, with DDE */
2283  {"", "[open(\"%1\")]", "shlexec", "dde", NULL, 0, "[open(\"%s\")]"},
2284  {"\"%1\"", "[open(\"%1\")]", "shlexec", "dde", NULL, 1, "[open(\"%s\")]"},
2285 
2286  /* Test unquoted %1 in command and ddeexec
2287  * (test filename has space) */
2288  {"%1", "[open(%1)]", "shlexec", "dde", NULL, 2, "[open(%s)]", TRUE /* before vista */},
2289 
2290  /* Test ifexec precedence over ddeexec */
2291  {"", "[open(\"%1\")]", "shlexec", "dde", "[ifexec(\"%1\")]", 0, "[ifexec(\"%s\")]"},
2292 
2293  /* Test default DDE topic */
2294  {"", "[open(\"%1\")]", "shlexec", NULL, NULL, 0, "[open(\"%s\")]"},
2295 
2296  /* Test default DDE application */
2297  {"", "[open(\"%1\")]", NULL, "dde", NULL, 0, "[open(\"%s\")]"},
2298 
2299  {NULL}
2300 };
2301 
2304 {
2306  if (winetest_debug > 1)
2307  trace("WaitForInputIdle() waiting for dde event timeout=min(%u,5s)\n", timeout);
2308  timeout = timeout < 5000 ? timeout : 5000;
2310 }
2311 
2312 /*
2313  * WaitForInputIdle() will normally return immediately for console apps. That's
2314  * a problem for us because ShellExecute will assume that an app is ready to
2315  * receive DDE messages after it has called WaitForInputIdle() on that app.
2316  * To work around that we install our own version of WaitForInputIdle() that
2317  * will wait for the child to explicitly tell us that it is ready. We do that
2318  * by changing the entry for WaitForInputIdle() in the shell32 import address
2319  * table.
2320  */
2321 static void hook_WaitForInputIdle(DWORD (WINAPI *new_func)(HANDLE, DWORD))
2322 {
2323  char *base;
2324  PIMAGE_NT_HEADERS nt_headers;
2325  DWORD import_directory_rva;
2326  PIMAGE_IMPORT_DESCRIPTOR import_descriptor;
2327  int hook_count = 0;
2328 
2329  base = (char *) GetModuleHandleA("shell32.dll");
2330  nt_headers = (PIMAGE_NT_HEADERS)(base + ((PIMAGE_DOS_HEADER) base)->e_lfanew);
2331  import_directory_rva = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
2332 
2333  /* Search for the correct imported module by walking the import descriptors */
2334  import_descriptor = (PIMAGE_IMPORT_DESCRIPTOR)(base + import_directory_rva);
2335  while (U(*import_descriptor).OriginalFirstThunk != 0)
2336  {
2337  char *import_module_name;
2338 
2339  import_module_name = base + import_descriptor->Name;
2340  if (lstrcmpiA(import_module_name, "user32.dll") == 0 ||
2341  lstrcmpiA(import_module_name, "user32") == 0)
2342  {
2343  PIMAGE_THUNK_DATA int_entry;
2344  PIMAGE_THUNK_DATA iat_entry;
2345 
2346  /* The import name table and import address table are two parallel
2347  * arrays. We need the import name table to find the imported
2348  * routine and the import address table to patch the address, so
2349  * walk them side by side */
2350  int_entry = (PIMAGE_THUNK_DATA)(base + U(*import_descriptor).OriginalFirstThunk);
2351  iat_entry = (PIMAGE_THUNK_DATA)(base + import_descriptor->FirstThunk);
2352  while (int_entry->u1.Ordinal != 0)
2353  {
2354  if (! IMAGE_SNAP_BY_ORDINAL(int_entry->u1.Ordinal))
2355  {
2356  PIMAGE_IMPORT_BY_NAME import_by_name;
2357  import_by_name = (PIMAGE_IMPORT_BY_NAME)(base + int_entry->u1.AddressOfData);
2358  if (lstrcmpA((char *) import_by_name->Name, "WaitForInputIdle") == 0)
2359  {
2360  /* Found the correct routine in the correct imported module. Patch it. */
2361  DWORD old_prot;
2362  VirtualProtect(&iat_entry->u1.Function, sizeof(ULONG_PTR), PAGE_READWRITE, &old_prot);
2363  iat_entry->u1.Function = (ULONG_PTR) new_func;
2364  VirtualProtect(&iat_entry->u1.Function, sizeof(ULONG_PTR), old_prot, &old_prot);
2365  if (winetest_debug > 1)
2366  trace("Hooked %s.WaitForInputIdle\n", import_module_name);
2367  hook_count++;
2368  break;
2369  }
2370  }
2371  int_entry++;
2372  iat_entry++;
2373  }
2374  break;
2375  }
2376 
2377  import_descriptor++;
2378  }
2379  ok(hook_count, "Could not hook WaitForInputIdle()\n");
2380 }
2381 
2382 static void test_dde(void)
2383 {
2384  char filename[MAX_PATH], defApplication[MAX_PATH];
2385  const dde_tests_t* test;
2386  char params[1024];
2387  INT_PTR rc;
2388  HANDLE map;
2389  char *shared_block;
2390  DWORD ddeflags;
2391 
2393 
2394  sprintf(filename, "%s\\test file.sde", tmpdir);
2395 
2396  /* Default service is application name minus path and extension */
2397  strcpy(defApplication, strrchr(argv0, '\\')+1);
2398  *strchr(defApplication, '.') = 0;
2399 
2401  4096, "winetest_shlexec_dde_map");
2402  shared_block = MapViewOfFile(map, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 4096);
2403 
2405  test = dde_tests;
2406  while (test->command)
2407  {
2408  if (!create_test_association(".sde"))
2409  {
2410  skip("Unable to create association for '.sde'\n");
2411  return;
2412  }
2413  create_test_verb_dde("shlexec.sde", "Open", 0, test->command, test->ddeexec,
2414  test->application, test->topic, test->ifexec);
2415 
2416  if (test->application != NULL || test->topic != NULL)
2417  {
2418  strcpy(shared_block, test->application ? test->application : defApplication);
2419  strcpy(shared_block + strlen(shared_block) + 1, test->topic ? test->topic : SZDDESYS_TOPIC);
2420  }
2421  else
2422  {
2423  shared_block[0] = '\0';
2424  shared_block[1] = '\0';
2425  }
2426  ddeExec[0] = 0;
2427 
2429  dde_ready_event = CreateEventA(NULL, TRUE, FALSE, "winetest_shlexec_dde_ready");
2430  rc = shell_execute_ex(ddeflags, NULL, filename, NULL, NULL, NULL);
2432  if (!(ddeflags & SEE_MASK_WAITFORINPUTIDLE) && rc == SE_ERR_DDEFAIL &&
2434  strcmp(winetest_platform, "windows") == 0)
2435  {
2436  /* Windows 10 does not call WaitForInputIdle() for DDE which creates
2437  * a race condition as the DDE server may not have time to start up.
2438  * When that happens the test fails with the above results and we
2439  * compensate by forcing the WaitForInputIdle() call.
2440  */
2441  trace("Adding SEE_MASK_WAITFORINPUTIDLE for Windows 10\n");
2442  ddeflags |= SEE_MASK_WAITFORINPUTIDLE;
2443  delete_test_association(".sde");
2445  continue;
2446  }
2447  okShell(32 < rc, "failed: rc=%lu err=%u\n", rc, GetLastError());
2448  if (test->ddeexec)
2450  broken(waitforinputidle_count == 0) /* Win10 race */,
2451  "WaitForInputIdle() was called %u times\n",
2453  else
2454  okShell(waitforinputidle_count == 0, "WaitForInputIdle() was called %u times for a non-DDE case\n", waitforinputidle_count);
2455 
2456  if (32 < rc)
2457  {
2458  if (test->broken)
2459  okChildIntBroken("argcA", test->expectedArgs + 3);
2460  else
2461  okChildInt("argcA", test->expectedArgs + 3);
2462 
2463  if (test->expectedArgs == 1) okChildPath("argvA3", filename);
2464 
2465  sprintf(params, test->expectedDdeExec, filename);
2466  okChildPath("ddeExec", params);
2467  }
2469 
2470  delete_test_association(".sde");
2471  test++;
2472  }
2473 
2474  UnmapViewOfFile(shared_block);
2475  CloseHandle(map);
2477 }
2478 
2479 #define DDE_DEFAULT_APP_VARIANTS 3
2480 typedef struct
2481 {
2482  const char* command;
2483  const char* expectedDdeApplication[DDE_DEFAULT_APP_VARIANTS];
2484  int todo;
2487 
2489 {
2490  /* There are three possible sets of results: Windows <= 2000, XP SP1 and
2491  * >= XP SP2. Use the first two tests to determine which results to expect.
2492  */
2493 
2494  /* Test unquoted existing filename with a space */
2495  {"%s\\test file.exe", {"test file", "test file", "test"}, 0x0, {33, 33, 33}},
2496  {"%s\\test2 file.exe", {"test2", "", "test2"}, 0x0, {33, 5, 33}},
2497 
2498  /* Test unquoted existing filename with a space */
2499  {"%s\\test file.exe param", {"test file", "test file", "test"}, 0x0, {33, 33, 33}},
2500 
2501  /* Test quoted existing filename with a space */
2502  {"\"%s\\test file.exe\"", {"test file", "test file", "test file"}, 0x0, {33, 33, 33}},
2503  {"\"%s\\test file.exe\" param", {"test file", "test file", "test file"}, 0x0, {33, 33, 33}},
2504 
2505  /* Test unquoted filename with a space that doesn't exist, but
2506  * test2.exe does */
2507  {"%s\\test2 file.exe param", {"test2", "", "test2"}, 0x0, {33, 5, 33}},
2508 
2509  /* Test quoted filename with a space that does not exist */
2510  {"\"%s\\test2 file.exe\"", {"", "", "test2 file"}, 0x0, {5, 2, 33}},
2511  {"\"%s\\test2 file.exe\" param", {"", "", "test2 file"}, 0x0, {5, 2, 33}},
2512 
2513  /* Test filename supplied without the extension */
2514  {"%s\\test2", {"test2", "", "test2"}, 0x0, {33, 5, 33}},
2515  {"%s\\test2 param", {"test2", "", "test2"}, 0x0, {33, 5, 33}},
2516 
2517  /* Test an unquoted nonexistent filename */
2518  {"%s\\notexist.exe", {"", "", "notexist"}, 0x0, {5, 2, 33}},
2519  {"%s\\notexist.exe param", {"", "", "notexist"}, 0x0, {5, 2, 33}},
2520 
2521  /* Test an application that will be found on the path */
2522  {"cmd", {"cmd", "cmd", "cmd"}, 0x0, {33, 33, 33}},
2523  {"cmd param", {"cmd", "cmd", "cmd"}, 0x0, {33, 33, 33}},
2524 
2525  /* Test an application that will not be found on the path */
2526  {"xyzwxyzwxyz", {"", "", "xyzwxyzwxyz"}, 0x0, {5, 2, 33}},
2527  {"xyzwxyzwxyz param", {"", "", "xyzwxyzwxyz"}, 0x0, {5, 2, 33}},
2528 
2529  {NULL, {NULL}, 0, {0}}
2530 };
2531 
2532 typedef struct
2533 {
2534  char *filename;
2537 
2539 {
2541  assert(info && info->filename);
2542  PostThreadMessageA(info->threadIdParent,
2543  WM_QUIT,
2545  0);
2546  ExitThread(0);
2547 }
2548 
2549 static void test_dde_default_app(void)
2550 {
2551  char filename[MAX_PATH];
2552  HSZ hszApplication;
2555  char params[1024];
2556  DWORD threadId;
2557  MSG msg;
2558  INT_PTR rc;
2559  int which = 0;
2560  HDDEDATA ret;
2561  BOOL b;
2562 
2564  ddeInst = 0;
2567  ok(rc == DMLERR_NO_ERROR, "got %lx\n", rc);
2568 
2569  sprintf(filename, "%s\\test file.sde", tmpdir);
2570 
2571  /* It is strictly not necessary to register an application name here, but wine's
2572  * DdeNameService implementation complains if 0 is passed instead of
2573  * hszApplication with DNS_FILTEROFF */
2574  hszApplication = DdeCreateStringHandleA(ddeInst, "shlexec", CP_WINANSI);
2576  ok(hszApplication && hszTopic, "got %p and %p\n", hszApplication, hszTopic);
2577  ret = DdeNameService(ddeInst, hszApplication, 0, DNS_REGISTER | DNS_FILTEROFF);
2578  ok(ret != 0, "got %p\n", ret);
2579 
2581  while (test->command)
2582  {
2583  HANDLE thread;
2584 
2585  if (!create_test_association(".sde"))
2586  {
2587  skip("Unable to create association for '.sde'\n");
2588  return;
2589  }
2590  sprintf(params, test->command, tmpdir);
2591  create_test_verb_dde("shlexec.sde", "Open", 1, params, "[test]", NULL,
2592  "shlexec", NULL);
2593  ddeApplication[0] = 0;
2594 
2595  /* No application will be run as we will respond to the first DDE event,
2596  * so don't wait for it */
2597  SetEvent(hEvent);
2598 
2599  thread = CreateThread(NULL, 0, ddeThread, &info, 0, &threadId);
2600  ok(thread != NULL, "got %p\n", thread);
2601  while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA(&msg);
2602  rc = msg.wParam > 32 ? 33 : msg.wParam;
2603 
2604  /* The first two tests determine which set of results to expect.
2605  * First check the platform as only the first set of results is
2606  * acceptable for Wine.
2607  */
2608  if (strcmp(winetest_platform, "wine"))
2609  {
2610  if (test == dde_default_app_tests)
2611  {
2612  if (strcmp(ddeApplication, test->expectedDdeApplication[0]))
2613  which = 2;
2614  }
2615  else if (test == dde_default_app_tests + 1)
2616  {
2617  if (which == 0 && rc == test->rc[1])
2618  which = 1;
2619  trace("DDE result variant %d\n", which);
2620  }
2621  }
2622 
2623  todo_wine_if(test->todo & 0x1)
2624  okShell(rc==test->rc[which], "failed: rc=%lu err=%u\n",
2625  rc, GetLastError());
2626  if (rc == 33)
2627  {
2628  todo_wine_if(test->todo & 0x2)
2629  ok(!strcmp(ddeApplication, test->expectedDdeApplication[which]),
2630  "Expected application '%s', got '%s'\n",
2631  test->expectedDdeApplication[which], ddeApplication);
2632  }
2634 
2635  delete_test_association(".sde");
2636  test++;
2637  }
2638 
2639  ret = DdeNameService(ddeInst, hszApplication, 0, DNS_UNREGISTER);
2640  ok(ret != 0, "got %p\n", ret);
2642  ok(b, "got %d\n", b);
2643  b = DdeFreeStringHandle(ddeInst, hszApplication);
2644  ok(b, "got %d\n", b);
2646  ok(b, "got %d\n", b);
2647 }
2648 
2649 static void init_test(void)
2650 {
2651  HMODULE hdll;
2652  HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO*);
2653  char filename[MAX_PATH];
2654  WCHAR lnkfile[MAX_PATH];
2655  char params[1024];
2656  const char* const * testfile;
2657  lnk_desc_t desc;
2658  DWORD rc;
2659  HRESULT r;
2660 
2661  hdll=GetModuleHandleA("shell32.dll");
2662  pDllGetVersion=(void*)GetProcAddress(hdll, "DllGetVersion");
2663  if (pDllGetVersion)
2664  {
2665  dllver.cbSize=sizeof(dllver);
2666  pDllGetVersion(&dllver);
2667  trace("major=%d minor=%d build=%d platform=%d\n",
2670  }
2671  else
2672  {
2673  memset(&dllver, 0, sizeof(dllver));
2674  }
2675 
2676  r = CoInitialize(NULL);
2677  ok(r == S_OK, "CoInitialize failed (0x%08x)\n", r);
2678  if (FAILED(r))
2679  exit(1);
2680 
2681  rc=GetModuleFileNameA(NULL, argv0, sizeof(argv0));
2682  ok(rc != 0 && rc < sizeof(argv0), "got %d\n", rc);
2684  {
2685  strcat(argv0, ".so");
2687  "unable to find argv0!\n");
2688  }
2689 
2690  /* Older versions (win 2k) fail tests if there is a space in
2691  the path. */
2692  if (dllver.dwMajorVersion <= 5)
2693  strcpy(filename, "c:\\");
2694  else
2695  GetTempPathA(sizeof(filename), filename);
2696  GetTempFileNameA(filename, "wt", 0, tmpdir);
2697  GetLongPathNameA(tmpdir, tmpdir, sizeof(tmpdir));
2698  DeleteFileA( tmpdir );
2699  rc = CreateDirectoryA( tmpdir, NULL );
2700  ok( rc, "failed to create %s err %u\n", tmpdir, GetLastError() );
2701  /* Set %TMPDIR% for the tests */
2702  SetEnvironmentVariableA("TMPDIR", tmpdir);
2703 
2704  rc = GetTempFileNameA(tmpdir, "wt", 0, child_file);
2705  ok(rc != 0, "got %d\n", rc);
2707 
2708  /* Set up the test files */
2709  testfile=testfiles;
2710  while (*testfile)
2711  {
2712  HANDLE hfile;
2713 
2714  sprintf(filename, *testfile, tmpdir);
2717  if (hfile==INVALID_HANDLE_VALUE)
2718  {
2719  trace("unable to create '%s': err=%u\n", filename, GetLastError());
2720  assert(0);
2721  }
2722  CloseHandle(hfile);
2723  testfile++;
2724  }
2725 
2726  /* Setup the test shortcuts */
2727  sprintf(filename, "%s\\test_shortcut_shlexec.lnk", tmpdir);
2728  MultiByteToWideChar(CP_ACP, 0, filename, -1, lnkfile, ARRAY_SIZE(lnkfile));
2729  desc.description=NULL;
2730  desc.workdir=NULL;
2731  sprintf(filename, "%s\\test file.shlexec", tmpdir);
2732  desc.path=filename;
2733  desc.pidl=NULL;
2734  desc.arguments="ignored";
2735  desc.showcmd=0;
2736  desc.icon=NULL;
2737  desc.icon_id=0;
2738  desc.hotkey=0;
2739  create_lnk(lnkfile, &desc, 0);
2740 
2741  sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir);
2742  MultiByteToWideChar(CP_ACP, 0, filename, -1, lnkfile, ARRAY_SIZE(lnkfile));
2743  desc.description=NULL;
2744  desc.workdir=NULL;
2745  desc.path=argv0;
2746  desc.pidl=NULL;
2747  sprintf(params, "shlexec \"%s\" Lnk", child_file);
2748  desc.arguments=params;
2749  desc.showcmd=0;
2750  desc.icon=NULL;
2751  desc.icon_id=0;
2752  desc.hotkey=0;
2753  create_lnk(lnkfile, &desc, 0);
2754 
2755  /* Create a basic association suitable for most tests */
2756  if (!create_test_association(".shlexec"))
2757  {
2759  skip("Unable to create association for '.shlexec'\n");
2760  return;
2761  }
2762  create_test_verb("shlexec.shlexec", "Open", 0, "Open \"%1\"");
2763  create_test_verb("shlexec.shlexec", "NoQuotes", 0, "NoQuotes %1");
2764  create_test_verb("shlexec.shlexec", "LowerL", 0, "LowerL %l");
2765  create_test_verb("shlexec.shlexec", "QuotedLowerL", 0, "QuotedLowerL \"%l\"");
2766  create_test_verb("shlexec.shlexec", "UpperL", 0, "UpperL %L");
2767  create_test_verb("shlexec.shlexec", "QuotedUpperL", 0, "QuotedUpperL \"%L\"");
2768 
2769  create_test_association(".sha");
2770  create_test_verb("shlexec.sha", "averb", 0, "AVerb \"%1\"");
2771 
2772  create_test_class("shlproto", TRUE);
2773  create_test_verb("shlproto", "open", 0, "URL \"%1\"");
2774  create_test_verb("shlproto", "averb", 0, "AVerb \"%1\"");
2775 
2776  /* Set an environment variable to see if it is inherited */
2777  SetEnvironmentVariableA("ShlexecVar", "Present");
2778 }
2779 
2780 static void cleanup_test(void)
2781 {
2782  char filename[MAX_PATH];
2783  const char* const * testfile;
2784 
2785  /* Delete the test files */
2786  testfile=testfiles;
2787  while (*testfile)
2788  {
2789  sprintf(filename, *testfile, tmpdir);
2790  /* Make sure we can delete the files ('test file.noassoc' is read-only now) */
2793  testfile++;
2794  }
2797 
2798  /* Delete the test association */
2799  delete_test_association(".shlexec");
2800  delete_test_association(".sha");
2801  delete_test_class("shlproto");
2802 
2804 
2805  CoUninitialize();
2806 }
2807 
2808 static void test_directory(void)
2809 {
2810  char path[MAX_PATH], curdir[MAX_PATH];
2811  char params[1024], dirpath[1024];
2812  INT_PTR rc;
2813 
2814  sprintf(path, "%s\\test2.exe", tmpdir);
2816 
2817  sprintf(params, "shlexec \"%s\" Exec", child_file);
2818 
2819  /* Test with the current directory */
2820  GetCurrentDirectoryA(sizeof(curdir), curdir);
2823  NULL, "test2.exe", params, NULL, NULL);
2824  okShell(rc > 32, "returned %lu\n", rc);
2825  okChildInt("argcA", 4);
2826  okChildString("argvA3", "Exec");
2827  okChildPath("longPath", path);
2828  SetCurrentDirectoryA(curdir);
2829 
2831  NULL, "test2.exe", params, NULL, NULL);
2832  okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
2833 
2834  /* Explicitly specify the directory to use */
2836  NULL, "test2.exe", params, tmpdir, NULL);
2837  okShell(rc > 32, "returned %lu\n", rc);
2838  okChildInt("argcA", 4);
2839  okChildString("argvA3", "Exec");
2840  okChildPath("longPath", path);
2841 
2842  /* Specify it through an environment variable */
2844  NULL, "test2.exe", params, "%TMPDIR%", NULL);
2845  todo_wine okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
2846 
2848  NULL, "test2.exe", params, "%TMPDIR%", NULL);
2849  okShell(rc > 32, "returned %lu\n", rc);
2850  okChildInt("argcA", 4);
2851  okChildString("argvA3", "Exec");
2852  okChildPath("longPath", path);
2853 
2854  /* Not a colon-separated directory list */
2855  sprintf(dirpath, "%s:%s", curdir, tmpdir);
2857  NULL, "test2.exe", params, dirpath, NULL);
2858  okShell(rc == SE_ERR_FNF, "returned %lu\n", rc);
2859 }
2860 
2861 START_TEST(shlexec)
2862 {
2863 
2865  if (myARGC >= 3)
2866  {
2867  doChild(myARGC, myARGV);
2868  /* Skip the tests/failures trace for child processes */
2870  }
2871 
2872  init_test();
2873 
2875  test_argify();
2877  test_filename();
2878  test_fileurls();
2879  test_urls();
2881  test_lnks();
2882  test_exes();
2883  test_dde();
2885  test_directory();
2886 
2887  cleanup_test();
2888 }
#define DNS_UNREGISTER
Definition: ddeml.h:153
const char * cmd
Definition: shlexec.c:1152
HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
Definition: shlexec.cpp:2179
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
static char shell_call[2048]
Definition: shlexec.c:348
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:600
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
#define HRESULT
Definition: msvc.h:7
static int argc
Definition: ServiceArgs.c:12
DWORD dwMinorVersion
Definition: shlwapi.h:1956
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExA(LPSHELLEXECUTEINFOA sei)
Definition: shlexec.cpp:2213
LONG winetest_get_failures(void)
#define trace_(file, line,...)
Definition: kmt_test.h:221
#define SEE_MASK_FLAG_DDEWAIT
Definition: shellapi.h:34
#define max(a, b)
Definition: svc.c:63
#define USE_COLON
Definition: shlexec.c:1747
LRESULT WINAPI DispatchMessageA(_In_ const MSG *)
struct S2 s2
#define CloseHandle
Definition: compat.h:487
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
void winetest_add_failures(LONG new_failures)
#define CBF_FAIL_ADVISES
Definition: ddeml.h:105
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]
Definition: ntddk_ex.h:178
static char * getChildString(const char *sect, const char *key)
Definition: shlexec.c:127
#define ERROR_SUCCESS
Definition: deptool.c:10
int WINAPI lstrcmpiA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:42
#define shell_execute_ex(mask, verb, filename, parameters, directory, class)
Definition: shlexec.c:674
const char * basename
Definition: shlexec.c:1741
#define MapViewOfFile
Definition: compat.h:493
static static const char __ms_va_list
Definition: printf.c:76
#define KEY_SET_VALUE
Definition: nt_native.h:1017
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
#define strcasecmp
Definition: fake.h:9
static void test_argify(void)
Definition: shlexec.c:1545
#define SEE_MASK_WAITFORINPUTIDLE
Definition: shellapi.h:56
static void test_fileurls(void)
Definition: shlexec.c:1786
BOOL broken
Definition: shlexec.c:2271
static void doChild(int argc, char **argv)
Definition: shlexec.c:208
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
static DWORD WINAPI hooked_WaitForInputIdle(HANDLE process, DWORD timeout)
Definition: shlexec.c:2303
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
Definition: ftp_var.h:139
#define SEE_MASK_NOCLOSEPROCESS
Definition: shellapi.h:31
#define KEY_READ
Definition: nt_native.h:1023
#define TRUE
Definition: types.h:120
static void test_exes(void)
Definition: shlexec.c:2204
#define SW_HIDE
Definition: winuser.h:762
static BOOL create_test_class(const char *class, BOOL protocol)
Definition: shlexec.c:684
const char * command
Definition: shlexec.c:2264
LONG WINAPI RegQueryInfoKeyA(HKEY hKey, LPSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen, LPDWORD lpcMaxClassLen, LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime)
Definition: reg.c:3607
LRESULT WINAPI SendMessageA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
char * wine_dbgstr_w(const wchar_t *wstr)
Definition: atltest.h:87
BOOL WINAPI GetExitCodeProcess(IN HANDLE hProcess, IN LPDWORD lpExitCode)
Definition: proc.c:1168
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
static void delete_test_class(const char *classname)
Definition: shlexec.c:800
#define SEE_MASK_NO_CONSOLE
Definition: shellapi.h:38
#define CP_ACP
Definition: compat.h:109
static GLenum which
Definition: wgl_font.c:159
int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:170
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define okChildIntBroken(key, expected)
Definition: shlexec.c:469
static fileurl_tests_t fileurl_tests[]
Definition: shlexec.c:1750
#define okChildInt(key, expected)
Definition: shlexec.c:460
char CHAR
Definition: xmlstorage.h:175
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1827
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
#define XTYP_EXECUTE
Definition: ddeml.h:185
#define U(x)
Definition: wordpad.c:45
#define SE_ERR_ACCESSDENIED
Definition: shellapi.h:124
#define CALLBACK
Definition: compat.h:35
static char * decodeA(const char *str)
Definition: shlexec.c:95
static void test_lpFile_parsed(void)
Definition: shlexec.c:1092
#define equal(x, y)
Definition: reader.cc:56
#define WM_QUIT
Definition: winuser.h:1605
UINT WINAPI GetSystemDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2282
const char * basename
Definition: shlexec.c:1034
BOOL WINAPI GetMessageA(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT)
BOOL WINAPI PostThreadMessageA(_In_ DWORD, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
const char * expectedDdeExec
Definition: shlexec.c:2270
LONG WINAPI RegOpenKeyExA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey, _In_ DWORD ulOptions, _In_ REGSAM samDesired, _Out_ PHKEY phkResult)
Definition: reg.c:3331
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:479
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1487
int WINAPI lstrcmpA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:18
struct _IMAGE_IMPORT_DESCRIPTOR * PIMAGE_IMPORT_DESCRIPTOR
#define assert(x)
Definition: debug.h:53
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
GLuint buffer
Definition: glext.h:5915
struct _IMAGE_IMPORT_BY_NAME * PIMAGE_IMPORT_BY_NAME
char * cmd
Definition: vfdcmd.c:85
const char * topic
Definition: shlexec.c:2267
BOOL WINAPI CopyFileA(IN LPCSTR lpExistingFileName, IN LPCSTR lpNewFileName, IN BOOL bFailIfExists)
Definition: copy.c:404
void * arg
Definition: msvc.h:10
#define CBF_FAIL_POKES
Definition: ddeml.h:107
Definition: dhcpd.h:245
#define test
Definition: rosglue.h:37
static char ddeApplication[MAX_PATH]
Definition: shlexec.c:149
#define shell_execute(verb, filename, parameters, directory)
Definition: shlexec.c:569
WCHAR classname[128]
Definition: startup.c:15
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
#define okChildStringBroken(key, expected, broken)
Definition: shlexec.c:384
__u16 time
Definition: mkdosfs.c:366
int32_t INT_PTR
Definition: typedefs.h:64
static HANDLE hEvent
Definition: shlexec.c:189
#define argv
Definition: mplay32.c:18
BOOL WINAPI DdeFreeDataHandle(HDDEDATA)
Definition: ddemisc.c:1461
const char * filename
Definition: ioapi.h:135
const char * verb
Definition: shlexec.c:1413
static int StrCmpPath(const char *s1, const char *s2)
Definition: shlexec.c:386
static void okChildPath_(const char *file, int line, const char *key, const char *expected)
Definition: shlexec.c:423
Definition: match.c:390
int32_t INT
Definition: typedefs.h:58
int winetest_debug
DWORD WINAPI GetModuleFileNameA(HINSTANCE hModule, LPSTR lpFilename, DWORD nSize)
Definition: loader.c:539
static const argify_tests_t argify_tests[]
Definition: shlexec.c:1420
#define DNS_REGISTER
Definition: ddeml.h:152
GLbitfield GLuint64 timeout
Definition: glext.h:7164
static void * heap_alloc(size_t len)
Definition: appwiz.h:65
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define CBF_FAIL_REQUESTS
Definition: ddeml.h:108
INT WINAPI GetPrivateProfileStringA(LPCSTR section, LPCSTR entry, LPCSTR def_val, LPSTR buffer, UINT len, LPCSTR filename)
Definition: profile.c:1204
DWORD WINAPI GetLongPathNameA(IN LPCSTR lpszShortPath, OUT LPSTR lpszLongPath, IN DWORD cchBuffer)
Definition: path.c:1670
static BOOL test_one_cmdline(const cmdline_tests_t *test)
Definition: shlexec.c:1318
#define sprintf(buf, format,...)
Definition: sprintf.c:55
int expectedArgs
Definition: shlexec.c:2269
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
static void create_test_verb(const char *classname, const char *verb, int rawcmd, const char *cmdtail)
Definition: shlexec.c:915
static DLLVERSIONINFO dllver
Definition: shlexec.c:54
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLenum GLint GLuint mask
Definition: glext.h:6028
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
unsigned char * LPBYTE
Definition: typedefs.h:53
#define FALSE
Definition: types.h:117
GLenum const GLfloat * params
Definition: glext.h:5645
DWORD e_lfanew
Definition: crypt.c:1156
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
DWORD dwBuildNumber
Definition: shlwapi.h:1957
static void cleanup_test(void)
Definition: shlexec.c:2780
unsigned int BOOL
Definition: ntddk_ex.h:94
WCHAR strW[12]
Definition: clipboard.c:2029
GLuint base
Definition: 3dtext.c:35
long LONG
Definition: pedump.c:60
static filename_tests_t noquotes_tests[]
Definition: shlexec.c:1082
HANDLE WINAPI DECLSPEC_HOTPATCH OpenEventA(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCSTR lpName)
Definition: synch.c:669
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
static void test_find_executable(void)
Definition: shlexec.c:1963
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
Definition: fileinfo.c:636
static const WCHAR desc[]
Definition: protectdata.c:36
HINSTANCE hInstApp
Definition: shellapi.h:317
const char * ifexec
Definition: shlexec.c:2268
#define GENERIC_WRITE
Definition: nt_native.h:90
static filename_tests_t filename_tests[]
Definition: shlexec.c:1039
#define DMLERR_NO_ERROR
Definition: ddeml.h:242
static PVOID ptr
Definition: dispmode.c:27
DWORD WINAPI DdeQueryStringA(DWORD, HSZ, LPSTR, DWORD, INT)
Definition: ddemisc.c:501
GLenum condition
Definition: glext.h:9255
LPWSTR *WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int *numargs)
Definition: shell32_main.c:79
const WCHAR * str
BOOL WINAPI DdeUninitialize(DWORD)
Definition: ddemisc.c:1112
static void okChildString_(const char *file, int line, const char *key, const char *expected, const char *bad)
Definition: shlexec.c:370
const char * command
Definition: shlexec.c:2482
BOOL WINAPI CreateDirectoryA(IN LPCSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:37
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:136
#define URL_SUCCESS
Definition: shlexec.c:1746
DWORD dwMajorVersion
Definition: shlwapi.h:1955
smooth NULL
Definition: ftsmooth.c:416
static void CALLBACK childTimeout(HWND wnd, UINT msg, UINT_PTR timer, DWORD time)
Definition: shlexec.c:201
#define SEE_MASK_FLAG_NO_UI
Definition: shellapi.h:36
static void strcat_param(char *str, const char *name, const char *param)
Definition: shlexec.c:478
static void test_dde_default_app(void)
Definition: shlexec.c:2549
static void test_directory(void)
Definition: shlexec.c:2808
BOOL WINAPI DeleteFileA(IN LPCSTR lpFileName)
Definition: delete.c:24
#define DDE_DEFAULT_APP_VARIANTS
Definition: shlexec.c:2479
Definition: parser.c:48
static LSTATUS myRegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
Definition: shlexec.c:734
BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
Definition: fileinfo.c:776
const char * winetest_platform
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventA(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCSTR lpName OPTIONAL)
Definition: synch.c:637
#define okChildString(key, expected)
Definition: shlexec.c:383
#define FILE_MAP_READ
Definition: compat.h:524
VOID WINAPI ExitThread(IN DWORD uExitCode)
Definition: thread.c:364
#define SE_ERR_DDEFAIL
Definition: shellapi.h:130
const char * LPCSTR
Definition: xmlstorage.h:183
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
static void test_filename(void)
Definition: shlexec.c:1603
DWORD WINAPI GetCurrentThreadId(VOID)
Definition: thread.c:458
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define b
Definition: ke_i.h:79
static DWORD ddeInst
Definition: shlexec.c:147
#define todo_wine_if(is_todo)
Definition: test.h:163
INT WINAPI DdeCmpStringHandles(HSZ, HSZ)
Definition: ddemisc.c:685
#define XTYP_CONNECT
Definition: ddeml.h:186
int toupper(int c)
Definition: utclib.c:881
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
static int myARGC
Definition: shlexec.c:50
#define SEE_MASK_NOZONECHECKS
Definition: shellapi.h:54
union _IMAGE_THUNK_DATA32::@2106 u1
#define SEE_MASK_CLASSNAME
Definition: shellapi.h:25
#define DNS_FILTEROFF
Definition: ddeml.h:155
static DWORD CALLBACK ddeThread(LPVOID arg)
Definition: shlexec.c:2538
#define WAIT_OBJECT_0
Definition: winbase.h:387
GLsizeiptr size
Definition: glext.h:5919
static char tmpdir[MAX_PATH]
Definition: shlexec.c:52
LONG WINAPI RegEnumValueA(_In_ HKEY hKey, _In_ DWORD dwIndex, _Out_ LPSTR lpName, _Inout_ LPDWORD lpcbName, _Reserved_ LPDWORD lpdwReserved, _Out_opt_ LPDWORD lpdwType, _Out_opt_ LPBYTE lpData, _Inout_opt_ LPDWORD lpcbData)
Definition: reg.c:2691
#define trace
Definition: atltest.h:70
#define GetEnvironmentVariableA(x, y, z)
Definition: compat.h:502
static void init_event(const char *child_file)
Definition: shlexec.c:190
BOOL WINAPI DdeFreeStringHandle(DWORD, HSZ)
Definition: ddemisc.c:631
__wchar_t WCHAR
Definition: xmlstorage.h:180
static void test_lnks(void)
Definition: shlexec.c:2110
void __winetest_cdecl winetest_ok(int condition, const char *msg,...)
LPCSTR lpParameters
Definition: shellapi.h:314
static dde_tests_t dde_tests[]
Definition: shlexec.c:2274
LONG HRESULT
Definition: typedefs.h:79
static const WCHAR url[]
Definition: encode.c:1432
struct S1 s1
static void reset_association_description(void)
Definition: shlexec.c:365
static const cmdline_tests_t cmdline_tests[]
Definition: shlexec.c:1157
BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableA(IN LPCSTR lpName, IN LPCSTR lpValue)
Definition: environ.c:218
static BOOL post_quit_on_execute
Definition: shlexec.c:150
#define WM_CLOSE
Definition: winuser.h:1603
#define FILE_MAP_WRITE
Definition: winbase.h:154
DWORD WINAPI GetShortPathNameA(IN LPCSTR lpszLongPath, OUT LPSTR lpszShortPath, IN DWORD cchBuffer)
Definition: path.c:1751
GLfloat param
Definition: glext.h:5796
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
#define SEE_MASK_DOENVSUBST
Definition: shellapi.h:35
#define DDE_FACK
Definition: ddeml.h:216
const GLubyte * c
Definition: glext.h:8905
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
static HDDEDATA CALLBACK ddeCb(UINT uType, UINT uFmt, HCONV hConv, HSZ hsz1, HSZ hsz2, HDDEDATA hData, ULONG_PTR dwData1, ULONG_PTR dwData2)
Definition: shlexec.c:153
PVOID HANDLE
Definition: typedefs.h:73
unsigned long DWORD
Definition: ntddk_ex.h:95
BOOL NTAPI VirtualProtect(IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD flNewProtect, OUT PDWORD lpflOldProtect)
Definition: virtmem.c:144
static void init_test(void)
Definition: shlexec.c:2649
#define success(from, fromstr, to, tostr)
#define SetLastError(x)
Definition: compat.h:500
#define USE_BSLASH
Definition: shlexec.c:1748
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
Definition: _map.h:44
static LSTATUS(WINAPI *pRegDeleteTreeW)(HKEY
int winetest_get_mainargs(char ***pargv)
static void delete_test_association(const char *extension)
Definition: shlexec.c:805
#define SZDDESYS_TOPIC
Definition: ddeml.h:47
#define WAIT_TIMEOUT
Definition: dderror.h:14
static DWORD get_long_path_name(const char *shortpath, char *longpath, DWORD longlen)
Definition: shlexec.c:930
LPSTR WINAPI GetCommandLineA(VOID)
Definition: proc.c:2005
HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
Definition: shlexec.cpp:1223
static HANDLE thread
Definition: service.c:33
static INT_PTR shell_execute_ex_(const char *file, int line, DWORD mask, LPCSTR verb, LPCSTR filename, LPCSTR parameters, LPCSTR directory, LPCSTR class)
Definition: shlexec.c:572
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
int ret
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define todo_wine
Definition: test.h:162
static int waitforinputidle_count
Definition: shlexec.c:2302
static const WCHAR space[]
Definition: ConsoleCP.c:24
HKEY key
Definition: reg.c:42
BOOL WINAPI SetCurrentDirectoryA(IN LPCSTR lpPathName)
Definition: path.c:2205
GLenum GLsizei len
Definition: glext.h:6722
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
static char argv0[MAX_PATH]
Definition: shlexec.c:49
GLdouble s
Definition: gl.h:2039
DWORD dwPlatformID
Definition: shlwapi.h:1958
static void okChildIntBroken_(const char *file, int line, const char *key, int expected)
Definition: shlexec.c:462
_In_ HANDLE hFile
Definition: mswsock.h:90
#define okShell
Definition: shlexec.c:362
LPCSTR lpDirectory
Definition: shellapi.h:315
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184
static HSZ hszTopic
Definition: shlexec.c:148
#define WINAPIV
Definition: sdbpapi.h:64
#define broken(x)
Definition: _sntprintf.h:21
HWND WINAPI FindWindowA(_In_opt_ LPCSTR, _In_opt_ LPCSTR)
static char ** myARGV
Definition: shlexec.c:51
LONG WINAPI RegDeleteKeyA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey)
Definition: reg.c:1222
const char * params
Definition: shlexec.c:1414
#define S_OK
Definition: intsafe.h:51
#define CREATE_ALWAYS
Definition: disk.h:72
#define SE_ERR_PNF
Definition: shellapi.h:123
#define SW_SHOWNORMAL
Definition: winuser.h:764
#define CP_WINANSI
Definition: ddeml.h:32
static const char * testfiles[]
Definition: shlexec.c:1005
#define IMAGE_SNAP_BY_ORDINAL(Ordinal)
Definition: ntimage.h:567
DWORD WINAPI GetTempPathA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2053
#define SE_ERR_FNF
Definition: shellapi.h:122
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
#define create_lnk(a, b, c)
Definition: shell32_test.h:37
void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
Definition: compobj.c:2067
HANDLE NTAPI OpenFileMappingA(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCSTR lpName)
Definition: filemap.c:284
#define ARRAY_SIZE(a)
Definition: main.h:24
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1577
START_TEST(shlexec)
Definition: shlexec.c:2861
#define ok(value,...)
Definition: atltest.h:57
DWORD WINAPI GetCurrentDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2145
int __cdecl vsprintf(char *_Dest, const char *_Format, va_list _Args)
Definition: sprintf.c:733
LONG WINAPI RegDeleteValueA(HKEY hKey, LPCSTR lpValueName)
Definition: reg.c:2319
static const char topic[]
Definition: propsys.c:44
static void test_urls(void)
Definition: shlexec.c:1869
BOOL WINAPI RemoveDirectoryA(IN LPCSTR lpPathName)
Definition: dir.c:714
DWORD threadIdParent
Definition: shlexec.c:2535
const char * cmd
Definition: shlexec.c:1416
DWORD WINAPI DdeGetData(HDDEDATA, LPBYTE, DWORD, DWORD)
Definition: ddemisc.c:1379
unsigned int UINT
Definition: ndis.h:50
#define __ms_va_end(list)
Definition: windef.h:458
HDDEDATA WINAPI DdeNameService(DWORD, HSZ, HSZ, UINT)
Definition: ddeserver.c:154
const char * broken
Definition: shlexec.c:1417
static PVOID hdll
Definition: shimdbg.c:126
#define lstrcpynA
Definition: compat.h:499
#define MultiByteToWideChar
Definition: compat.h:110
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG _In_ LONG _In_ LONG x2
Definition: winddi.h:3706
char * strchr(const char *String, int ch)
Definition: utclib.c:501
static void create_test_verb_dde(const char *classname, const char *verb, int rawcmd, const char *cmdtail, const char *ddeexec, const char *application, const char *topic, const char *ifexec)
Definition: shlexec.c:814
static void okChildInt_(const char *file, int line, const char *key, int expected)
Definition: shlexec.c:453
#define IMAGE_DIRECTORY_ENTRY_IMPORT
Definition: pedump.c:260
#define skip(...)
Definition: atltest.h:64
HRESULT WINAPI CoInitialize(LPVOID lpReserved)
Definition: compobj.c:1964
#define todo_wait
Definition: shlexec.c:492
#define msg(x)
Definition: auth_time.c:54
#define okChildPath(key, expected)
Definition: shlexec.c:451
#define CBF_SKIP_ALLNOTIFICATIONS
Definition: ddeml.h:115
#define __ms_va_start(list, arg)
Definition: windef.h:457
Definition: name.c:38
DWORD WINAPI WaitForInputIdle(_In_ HANDLE, _In_ DWORD)
static int bad_shellexecute
Definition: shlexec.c:494
const char * ddeexec
Definition: shlexec.c:2265
const char * verb
Definition: shlexec.c:1033
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
HSZ WINAPI DdeCreateStringHandleA(DWORD, LPCSTR, INT)
Definition: ddemisc.c:577
#define c
Definition: ke_i.h:80
static const char * encodeA(const char *str)
Definition: shlexec.c:67
static dde_default_app_tests_t dde_default_app_tests[]
Definition: shlexec.c:2488
FILE * stderr
#define const
Definition: zconf.h:230
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
static BOOL skip_noassoc_tests
Definition: shlexec.c:56
#define EVENT_MODIFY_STATE
Definition: winbase.h:163
#define ULONG_PTR
Definition: config.h:101
char * cleanup(char *str)
Definition: wpickclick.c:99
static const WCHAR sp[]
Definition: suminfo.c:288
#define okShell_(file, line)
Definition: shlexec.c:361
#define GetProcAddress(x, y)
Definition: compat.h:501
static void hook_WaitForInputIdle(DWORD(WINAPI *new_func)(HANDLE, DWORD))
Definition: shlexec.c:2321
static __ms_va_list valist
Definition: printf.c:64
static void WINAPIV WINETEST_PRINTF_ATTR(2, 3)
Definition: shlexec.c:115
#define HKEY_CLASSES_ROOT
Definition: winreg.h:10
#define SE_ERR_NOASSOC
Definition: shellapi.h:132
LONG WINAPI RegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE *lpData, DWORD cbData)
Definition: reg.c:4812
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:488
LONG WINAPI RegCreateKeyExA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey, _In_ DWORD Reserved, _In_ LPSTR lpClass, _In_ DWORD dwOptions, _In_ REGSAM samDesired, _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _Out_ PHKEY phkResult, _Out_ LPDWORD lpdwDisposition)
Definition: reg.c:1029
const char * application
Definition: shlexec.c:2266
void exit(int exitcode)
Definition: _exit.c:33
static char shortpath[MAX_PATH]
Definition: batch.c:32
GLfloat GLfloat p
Definition: glext.h:8902
#define CHILD_DDE_TIMEOUT
Definition: shlexec.c:146
static int _todo_wait
Definition: shlexec.c:491
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static void test_dde(void)
Definition: shlexec.c:2382
static HANDLE dde_ready_event
Definition: shlexec.c:57
BOOL WINAPI DECLSPEC_HOTPATCH WritePrivateProfileStringA(LPCSTR section, LPCSTR entry, LPCSTR string, LPCSTR filename)
Definition: profile.c:1484
#define UnmapViewOfFile
Definition: compat.h:494
UINT WINAPI GetPrivateProfileIntA(LPCSTR section, LPCSTR entry, INT def_val, LPCSTR filename)
Definition: profile.c:1326
GLuint64EXT * result
Definition: glext.h:11304
#define memset(x, y, z)
Definition: compat.h:39
static BOOL create_test_association(const char *extension)
Definition: shlexec.c:712
#define KEY_CREATE_SUB_KEY
Definition: nt_native.h:1018
#define args
Definition: format.c:66
static filename_tests_t lnk_tests[]
Definition: shlexec.c:2094
static INT_PTR shell_execute_(const char *file, int line, LPCSTR verb, LPCSTR filename, LPCSTR parameters, LPCSTR directory)
Definition: shlexec.c:496
#define win_skip
Definition: test.h:149
static char assoc_desc[2048]
Definition: shlexec.c:364
HANDLE WINAPI FindFirstFileA(IN LPCSTR lpFileName, OUT LPWIN32_FIND_DATAA lpFindFileData)
Definition: find.c:263
UINT WINAPI GetTempFileNameA(IN LPCSTR lpPathName, IN LPCSTR lpPrefixString, IN UINT uUnique, OUT LPSTR lpTempFileName)
Definition: filename.c:26
static unsigned decode_char(char c)
Definition: shlexec.c:87
static void dump_child_(const char *file, int line)
Definition: shlexec.c:312
Definition: dsound.c:943
__analysis_noreturn void WINAPI PostQuitMessage(_In_ int)
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:54
UINT WINAPI DdeInitializeA(LPDWORD, PFNCALLBACK, DWORD, DWORD)
Definition: ddemisc.c:1075
LONG WINAPI RegEnumKeyExA(_In_ HKEY hKey, _In_ DWORD dwIndex, _Out_ LPSTR lpName, _Inout_ LPDWORD lpcbName, _Reserved_ LPDWORD lpReserved, _Out_opt_ LPSTR lpClass, _Inout_opt_ LPDWORD lpcbClass, _Out_opt_ PFILETIME lpftLastWriteTime)
Definition: reg.c:2442
HANDLE NTAPI CreateFileMappingA(IN HANDLE hFile, IN LPSECURITY_ATTRIBUTES lpFileMappingAttributes, IN DWORD flProtect, IN DWORD dwMaximumSizeHigh, IN DWORD dwMaximumSizeLow, IN LPCSTR lpName)
Definition: filemap.c:23
PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA
Definition: ntimage.h:566
BOOL expected
Definition: store.c:2063
static void test_commandline2argv(void)
Definition: shlexec.c:1359
const char * urlprefix
Definition: shlexec.c:1740
static BOOL skip_shlexec_tests
Definition: shlexec.c:55
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint GLenum GLenum GLenum GLint GLuint GLenum GLenum GLfloat GLenum GLfloat GLenum map
Definition: glfuncs.h:262
Definition: path.c:41
static BOOL heap_free(void *mem)
Definition: appwiz.h:75
#define PAGE_READWRITE
Definition: nt_native.h:1304
static char ddeExec[MAX_PATH]
Definition: shlexec.c:149
PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS
Definition: ntddk_ex.h:187
Definition: fci.c:126
#define REG_SZ
Definition: layer.c:22
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
static char child_file[MAX_PATH]
Definition: shlexec.c:53