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