ReactOS  0.4.14-dev-114-gc8cbd56
process.c
Go to the documentation of this file.
1 /*
2  * Unit test suite for process functions
3  *
4  * Copyright 2002 Eric Pouech
5  * Copyright 2006 Dmitry Timoshkov
6  * Copyright 2014 Michael Müller
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "wincon.h"
34 #include "winnls.h"
35 #include "winternl.h"
36 #include "tlhelp32.h"
37 
38 #include "wine/test.h"
39 
40 #include "winnt.h"
41 
42 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
43 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
44 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
45 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
46 
47 #define expect_eq_d(expected, actual) \
48  do { \
49  int value = (actual); \
50  ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
51  (expected), value); \
52  } while (0)
53 #define expect_eq_s(expected, actual) \
54  do { \
55  LPCSTR value = (actual); \
56  ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
57  expected, value); \
58  } while (0)
59 #define expect_eq_ws_i(expected, actual) \
60  do { \
61  LPCWSTR value = (actual); \
62  ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
63  wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
64  } while (0)
65 
67 static void (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO);
68 static BOOL (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD);
69 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
70 static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
71 static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
72 static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize);
73 static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize);
74 static DWORD (WINAPI *pK32GetProcessImageFileNameA)(HANDLE,LPSTR,DWORD);
75 static HANDLE (WINAPI *pCreateJobObjectW)(LPSECURITY_ATTRIBUTES sa, LPCWSTR name);
76 static BOOL (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process);
77 static BOOL (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result);
78 static BOOL (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code);
79 static BOOL (WINAPI *pQueryInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len, LPDWORD ret_len);
80 static BOOL (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len);
81 static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads);
82 static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR);
83 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
84 static BOOL (WINAPI *pProcessIdToSessionId)(DWORD,DWORD*);
85 static DWORD (WINAPI *pWTSGetActiveConsoleSessionId)(void);
86 static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
87 static BOOL (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*);
88 static BOOL (WINAPI *pProcess32Next)(HANDLE, PROCESSENTRY32*);
89 static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*);
90 static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*);
91 static BOOL (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
92 static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
93 static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
94 static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
95 static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
96 static DWORD (WINAPI *pGetActiveProcessorCount)(WORD);
97 
98 /* ############################### */
99 static char base[MAX_PATH];
100 static char selfname[MAX_PATH];
101 static char* exename;
102 static char resfile[MAX_PATH];
103 
104 static int myARGC;
105 static char** myARGV;
106 
107 /* As some environment variables get very long on Unix, we only test for
108  * the first 127 bytes.
109  * Note that increasing this value past 256 may exceed the buffer size
110  * limitations of the *Profile functions (at least on Wine).
111  */
112 #define MAX_LISTED_ENV_VAR 128
113 
114 /* ---------------- portable memory allocation thingie */
115 
116 static char memory[1024*256];
117 static char* memory_index = memory;
118 
119 static char* grab_memory(size_t len)
120 {
121  char* ret = memory_index;
122  /* align on dword */
123  len = (len + 3) & ~3;
124  memory_index += len;
125  assert(memory_index <= memory + sizeof(memory));
126  return ret;
127 }
128 
129 static void release_memory(void)
130 {
132 }
133 
134 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
135 
136 static const char* encodeA(const char* str)
137 {
138  char* ptr;
139  size_t len,i;
140 
141  if (!str) return "";
142  len = strlen(str) + 1;
143  ptr = grab_memory(len * 2 + 1);
144  for (i = 0; i < len; i++)
145  sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
146  ptr[2 * len] = '\0';
147  return ptr;
148 }
149 
150 static const char* encodeW(const WCHAR* str)
151 {
152  char* ptr;
153  size_t len,i;
154 
155  if (!str) return "";
156  len = lstrlenW(str) + 1;
157  ptr = grab_memory(len * 4 + 1);
158  assert(ptr);
159  for (i = 0; i < len; i++)
160  sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
161  ptr[4 * len] = '\0';
162  return ptr;
163 }
164 
165 static unsigned decode_char(char c)
166 {
167  if (c >= '0' && c <= '9') return c - '0';
168  if (c >= 'a' && c <= 'f') return c - 'a' + 10;
169  assert(c >= 'A' && c <= 'F');
170  return c - 'A' + 10;
171 }
172 
173 static char* decodeA(const char* str)
174 {
175  char* ptr;
176  size_t len,i;
177 
178  len = strlen(str) / 2;
179  if (!len--) return NULL;
180  ptr = grab_memory(len + 1);
181  for (i = 0; i < len; i++)
182  ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
183  ptr[len] = '\0';
184  return ptr;
185 }
186 
187 /* This will be needed to decode Unicode strings saved by the child process
188  * when we test Unicode functions.
189  */
190 static WCHAR* decodeW(const char* str)
191 {
192  size_t len;
193  WCHAR* ptr;
194  int i;
195 
196  len = strlen(str) / 4;
197  if (!len--) return NULL;
198  ptr = (WCHAR*)grab_memory(len * 2 + 1);
199  for (i = 0; i < len; i++)
200  ptr[i] = (decode_char(str[4 * i]) << 12) |
201  (decode_char(str[4 * i + 1]) << 8) |
202  (decode_char(str[4 * i + 2]) << 4) |
203  (decode_char(str[4 * i + 3]) << 0);
204  ptr[len] = '\0';
205  return ptr;
206 }
207 
208 /******************************************************************
209  * init
210  *
211  * generates basic information like:
212  * base: absolute path to curr dir
213  * selfname: the way to reinvoke ourselves
214  * exename: executable without the path
215  * function-pointers, which are not implemented in all windows versions
216  */
217 static BOOL init(void)
218 {
219  char *p;
220 
222  if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
223  strcpy(selfname, myARGV[0]);
224 
225  /* Strip the path of selfname */
226  if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1;
227  else exename = selfname;
228 
229  if ((p = strrchr(exename, '/')) != NULL) exename = p + 1;
230 
231  hkernel32 = GetModuleHandleA("kernel32");
232  hntdll = GetModuleHandleA("ntdll.dll");
233 
234  pNtQueryInformationProcess = (void *)GetProcAddress(hntdll, "NtQueryInformationProcess");
235 
236  pGetNativeSystemInfo = (void *) GetProcAddress(hkernel32, "GetNativeSystemInfo");
237  pGetSystemRegistryQuota = (void *) GetProcAddress(hkernel32, "GetSystemRegistryQuota");
238  pIsWow64Process = (void *) GetProcAddress(hkernel32, "IsWow64Process");
239  pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
240  pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
241  pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA");
242  pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW");
243  pK32GetProcessImageFileNameA = (void *) GetProcAddress(hkernel32, "K32GetProcessImageFileNameA");
244  pCreateJobObjectW = (void *)GetProcAddress(hkernel32, "CreateJobObjectW");
245  pAssignProcessToJobObject = (void *)GetProcAddress(hkernel32, "AssignProcessToJobObject");
246  pIsProcessInJob = (void *)GetProcAddress(hkernel32, "IsProcessInJob");
247  pTerminateJobObject = (void *)GetProcAddress(hkernel32, "TerminateJobObject");
248  pQueryInformationJobObject = (void *)GetProcAddress(hkernel32, "QueryInformationJobObject");
249  pSetInformationJobObject = (void *)GetProcAddress(hkernel32, "SetInformationJobObject");
250  pCreateIoCompletionPort = (void *)GetProcAddress(hkernel32, "CreateIoCompletionPort");
251  pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode");
252  pProcessIdToSessionId = (void *)GetProcAddress(hkernel32, "ProcessIdToSessionId");
253  pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId");
254  pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
255  pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First");
256  pProcess32Next = (void *)GetProcAddress(hkernel32, "Process32Next");
257  pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First");
258  pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next");
259  pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
260  pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum");
261  pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
262  pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
263  pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
264  pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount");
265 
266  return TRUE;
267 }
268 
269 /******************************************************************
270  * get_file_name
271  *
272  * generates an absolute file_name for temporary file
273  *
274  */
275 static void get_file_name(char* buf)
276 {
277  char path[MAX_PATH];
278 
279  buf[0] = '\0';
280  GetTempPathA(sizeof(path), path);
281  GetTempFileNameA(path, "wt", 0, buf);
282 }
283 
284 /******************************************************************
285  * static void childPrintf
286  *
287  */
288 static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...)
289 {
290  va_list valist;
291  char buffer[1024+4*MAX_LISTED_ENV_VAR];
292  DWORD w;
293 
294  va_start(valist, fmt);
296  va_end(valist);
298 }
299 
300 
301 /******************************************************************
302  * doChild
303  *
304  * output most of the information in the child process
305  */
306 static void doChild(const char* file, const char* option)
307 {
308  RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
309  STARTUPINFOA siA;
310  STARTUPINFOW siW;
311  int i;
312  char *ptrA, *ptrA_save;
313  WCHAR *ptrW, *ptrW_save;
314  char bufA[MAX_PATH];
315  WCHAR bufW[MAX_PATH];
318  PROCESSENTRY32 pe;
319  BOOL ret;
320 
321  if (hFile == INVALID_HANDLE_VALUE) return;
322 
323  /* output of startup info (Ansi) */
324  GetStartupInfoA(&siA);
325  childPrintf(hFile,
326  "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
327  "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
328  "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
329  "dwFlags=%u\nwShowWindow=%u\n"
330  "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
331  siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
332  siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize,
334  siA.dwFlags, siA.wShowWindow,
336 
337  /* check the console handles in the TEB */
338  childPrintf(hFile, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
339  (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput,
340  (DWORD_PTR)params->hStdError);
341 
342  /* since GetStartupInfoW is only implemented in win2k,
343  * zero out before calling so we can notice the difference
344  */
345  memset(&siW, 0, sizeof(siW));
346  GetStartupInfoW(&siW);
347  childPrintf(hFile,
348  "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
349  "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
350  "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
351  "dwFlags=%u\nwShowWindow=%u\n"
352  "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
353  siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
354  siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize,
356  siW.dwFlags, siW.wShowWindow,
358 
359  /* Arguments */
360  childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
361  for (i = 0; i < myARGC; i++)
362  {
363  childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
364  }
365  childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
366  childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
367 
368  /* output toolhelp information */
369  snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
370  ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
371  memset(&pe, 0, sizeof(pe));
372  pe.dwSize = sizeof(pe);
373  if (pProcess32First(snapshot, &pe))
374  {
375  while (pe.th32ProcessID != GetCurrentProcessId())
376  if (!pProcess32Next(snapshot, &pe)) break;
377  }
379  ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n");
380  childPrintf(hFile,
381  "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n"
382  "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n"
383  "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n",
386  pe.dwFlags, encodeA(pe.szExeFile));
387 
388  /* output of environment (Ansi) */
389  ptrA_save = ptrA = GetEnvironmentStringsA();
390  if (ptrA)
391  {
393 
394  childPrintf(hFile, "[EnvironmentA]\n");
395  i = 0;
396  while (*ptrA)
397  {
399  childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
400  i++;
401  ptrA += strlen(ptrA) + 1;
402  }
403  childPrintf(hFile, "len=%d\n\n", i);
404  FreeEnvironmentStringsA(ptrA_save);
405  }
406 
407  /* output of environment (Unicode) */
408  ptrW_save = ptrW = GetEnvironmentStringsW();
409  if (ptrW)
410  {
412 
413  childPrintf(hFile, "[EnvironmentW]\n");
414  i = 0;
415  while (*ptrW)
416  {
418  env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
419  childPrintf(hFile, "env%d=%s\n", i, encodeW(env_var));
420  i++;
421  ptrW += lstrlenW(ptrW) + 1;
422  }
423  childPrintf(hFile, "len=%d\n\n", i);
424  FreeEnvironmentStringsW(ptrW_save);
425  }
426 
427  childPrintf(hFile, "[Misc]\n");
428  if (GetCurrentDirectoryA(sizeof(bufA), bufA))
429  childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
430  if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW))
431  childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
432  childPrintf(hFile, "\n");
433 
434  if (option && strcmp(option, "console") == 0)
435  {
439  DWORD modeIn, modeOut;
440 
441  childPrintf(hFile, "[Console]\n");
442  if (GetConsoleScreenBufferInfo(hConOut, &sbi))
443  {
444  childPrintf(hFile, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
445  sbi.dwSize.X, sbi.dwSize.Y, sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y, sbi.wAttributes);
446  childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
447  sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom);
448  childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n",
450  }
451  childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
453  if (GetConsoleMode(hConIn, &modeIn))
454  childPrintf(hFile, "InputMode=%u\n", modeIn);
455  if (GetConsoleMode(hConOut, &modeOut))
456  childPrintf(hFile, "OutputMode=%u\n", modeOut);
457 
458  /* now that we have written all relevant information, let's change it */
459  SetLastError(0xdeadbeef);
460  ret = SetConsoleCP(1252);
462  {
463  win_skip("Setting the codepage is not implemented\n");
464  }
465  else
466  {
467  ok(ret, "Setting CP\n");
468  ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
469  }
470 
471  ret = SetConsoleMode(hConIn, modeIn ^ 1);
472  ok( ret, "Setting mode (%d)\n", GetLastError());
473  ret = SetConsoleMode(hConOut, modeOut ^ 1);
474  ok( ret, "Setting mode (%d)\n", GetLastError());
475  sbi.dwCursorPosition.X ^= 1;
476  sbi.dwCursorPosition.Y ^= 1;
478  ok( ret, "Setting cursor position (%d)\n", GetLastError());
479  }
480  if (option && strcmp(option, "stdhandle") == 0)
481  {
484 
486  {
487  char buf[1024];
488  DWORD r, w;
489 
490  ok(ReadFile(hStdIn, buf, sizeof(buf), &r, NULL) && r > 0, "Reading message from input pipe\n");
491  childPrintf(hFile, "[StdHandle]\nmsg=%s\n\n", encodeA(buf));
492  ok(WriteFile(hStdOut, buf, r, &w, NULL) && w == r, "Writing message to output pipe\n");
493  }
494  }
495 
496  if (option && strcmp(option, "exit_code") == 0)
497  {
498  childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123);
500  ExitProcess(123);
501  }
502 
504 }
505 
506 static char* getChildString(const char* sect, const char* key)
507 {
508  char buf[1024+4*MAX_LISTED_ENV_VAR];
509  char* ret;
510 
511  GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
512  if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
513  assert(!(strlen(buf) & 1));
514  ret = decodeA(buf);
515  return ret;
516 }
517 
518 static WCHAR* getChildStringW(const char* sect, const char* key)
519 {
520  char buf[1024+4*MAX_LISTED_ENV_VAR];
521  WCHAR* ret;
522 
523  GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
524  if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
525  assert(!(strlen(buf) & 1));
526  ret = decodeW(buf);
527  return ret;
528 }
529 
530 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
531  * others... (windows uses stricmp while Un*x uses strcasecmp...)
532  */
533 static int wtstrcasecmp(const char* p1, const char* p2)
534 {
535  char c1, c2;
536 
537  c1 = c2 = '@';
538  while (c1 == c2 && c1)
539  {
540  c1 = *p1++; c2 = *p2++;
541  if (c1 != c2)
542  {
543  c1 = toupper(c1); c2 = toupper(c2);
544  }
545  }
546  return c1 - c2;
547 }
548 
549 static int strCmp(const char* s1, const char* s2, BOOL sensitive)
550 {
551  if (!s1 && !s2) return 0;
552  if (!s2) return -1;
553  if (!s1) return 1;
554  return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2);
555 }
556 
557 static void ok_child_string( int line, const char *sect, const char *key,
558  const char *expect, int sensitive )
559 {
560  char* result = getChildString( sect, key );
561  ok_(__FILE__, line)( strCmp(result, expect, sensitive) == 0, "%s:%s expected '%s', got '%s'\n",
562  sect, key, expect ? expect : "(null)", result );
563 }
564 
565 static void ok_child_stringWA( int line, const char *sect, const char *key,
566  const char *expect, int sensitive )
567 {
568  WCHAR* expectW;
569  CHAR* resultA;
570  DWORD len;
571  WCHAR* result = getChildStringW( sect, key );
572 
573  len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0);
574  expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
575  MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len);
576 
577  len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL);
578  resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR));
579  WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL);
580 
581  if (sensitive)
582  ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
583  sect, key, expect ? expect : "(null)", resultA );
584  else
585  ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
586  sect, key, expect ? expect : "(null)", resultA );
587  HeapFree(GetProcessHeap(),0,expectW);
588  HeapFree(GetProcessHeap(),0,resultA);
589 }
590 
591 static void ok_child_int( int line, const char *sect, const char *key, UINT expect )
592 {
594  ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result );
595 }
596 
597 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
598 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
599 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
600 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
601 
602 static void test_Startup(void)
603 {
604  char buffer[MAX_PATH];
607  char *result;
608  static CHAR title[] = "I'm the title string",
609  desktop[] = "winsta0\\default",
610  empty[] = "";
611 
612  /* let's start simplistic */
613  memset(&startup, 0, sizeof(startup));
614  startup.cb = sizeof(startup);
615  startup.dwFlags = STARTF_USESHOWWINDOW;
616  startup.wShowWindow = SW_SHOWNORMAL;
617 
619  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
620  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
621  /* wait for child to terminate */
622  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
623  /* child process has changed result file, so let profile functions know about it */
625  CloseHandle(info.hThread);
626  CloseHandle(info.hProcess);
627 
628  GetStartupInfoA(&si);
629  okChildInt("StartupInfoA", "cb", startup.cb);
630  okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
631  okChildInt("StartupInfoA", "dwX", startup.dwX);
632  okChildInt("StartupInfoA", "dwY", startup.dwY);
633  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
634  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
635  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
636  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
637  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
638  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
639  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
640  release_memory();
642 
643  /* not so simplistic now */
644  memset(&startup, 0, sizeof(startup));
645  startup.cb = sizeof(startup);
646  startup.dwFlags = STARTF_USESHOWWINDOW;
647  startup.wShowWindow = SW_SHOWNORMAL;
648  startup.lpTitle = title;
649  startup.lpDesktop = desktop;
650  startup.dwXCountChars = 0x12121212;
651  startup.dwYCountChars = 0x23232323;
652  startup.dwX = 0x34343434;
653  startup.dwY = 0x45454545;
654  startup.dwXSize = 0x56565656;
655  startup.dwYSize = 0x67676767;
656  startup.dwFillAttribute = 0xA55A;
657 
659  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
660  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
661  /* wait for child to terminate */
662  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
663  /* child process has changed result file, so let profile functions know about it */
665  CloseHandle(info.hThread);
666  CloseHandle(info.hProcess);
667 
668  okChildInt("StartupInfoA", "cb", startup.cb);
669  okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
670  okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
671  okChildInt("StartupInfoA", "dwX", startup.dwX);
672  okChildInt("StartupInfoA", "dwY", startup.dwY);
673  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
674  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
675  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
676  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
677  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
678  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
679  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
680  release_memory();
682 
683  /* not so simplistic now */
684  memset(&startup, 0, sizeof(startup));
685  startup.cb = sizeof(startup);
686  startup.dwFlags = STARTF_USESHOWWINDOW;
687  startup.wShowWindow = SW_SHOWNORMAL;
688  startup.lpTitle = title;
689  startup.lpDesktop = NULL;
690  startup.dwXCountChars = 0x12121212;
691  startup.dwYCountChars = 0x23232323;
692  startup.dwX = 0x34343434;
693  startup.dwY = 0x45454545;
694  startup.dwXSize = 0x56565656;
695  startup.dwYSize = 0x67676767;
696  startup.dwFillAttribute = 0xA55A;
697 
699  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
700  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
701  /* wait for child to terminate */
702  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
703  /* child process has changed result file, so let profile functions know about it */
705  CloseHandle(info.hThread);
706  CloseHandle(info.hProcess);
707 
708  okChildInt("StartupInfoA", "cb", startup.cb);
709  okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
710  okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
711  okChildInt("StartupInfoA", "dwX", startup.dwX);
712  okChildInt("StartupInfoA", "dwY", startup.dwY);
713  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
714  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
715  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
716  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
717  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
718  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
719  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
720  release_memory();
722 
723  /* not so simplistic now */
724  memset(&startup, 0, sizeof(startup));
725  startup.cb = sizeof(startup);
726  startup.dwFlags = STARTF_USESHOWWINDOW;
727  startup.wShowWindow = SW_SHOWNORMAL;
728  startup.lpTitle = title;
729  startup.lpDesktop = empty;
730  startup.dwXCountChars = 0x12121212;
731  startup.dwYCountChars = 0x23232323;
732  startup.dwX = 0x34343434;
733  startup.dwY = 0x45454545;
734  startup.dwXSize = 0x56565656;
735  startup.dwYSize = 0x67676767;
736  startup.dwFillAttribute = 0xA55A;
737 
739  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
740  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
741  /* wait for child to terminate */
742  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
743  /* child process has changed result file, so let profile functions know about it */
745  CloseHandle(info.hThread);
746  CloseHandle(info.hProcess);
747 
748  okChildInt("StartupInfoA", "cb", startup.cb);
749  okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
750  okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
751  okChildInt("StartupInfoA", "dwX", startup.dwX);
752  okChildInt("StartupInfoA", "dwY", startup.dwY);
753  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
754  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
755  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
756  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
757  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
758  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
759  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
760  release_memory();
762 
763  /* not so simplistic now */
764  memset(&startup, 0, sizeof(startup));
765  startup.cb = sizeof(startup);
766  startup.dwFlags = STARTF_USESHOWWINDOW;
767  startup.wShowWindow = SW_SHOWNORMAL;
768  startup.lpTitle = NULL;
769  startup.lpDesktop = desktop;
770  startup.dwXCountChars = 0x12121212;
771  startup.dwYCountChars = 0x23232323;
772  startup.dwX = 0x34343434;
773  startup.dwY = 0x45454545;
774  startup.dwXSize = 0x56565656;
775  startup.dwYSize = 0x67676767;
776  startup.dwFillAttribute = 0xA55A;
777 
779  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
780  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
781  /* wait for child to terminate */
782  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
783  /* child process has changed result file, so let profile functions know about it */
785  CloseHandle(info.hThread);
786  CloseHandle(info.hProcess);
787 
788  okChildInt("StartupInfoA", "cb", startup.cb);
789  okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
790  result = getChildString( "StartupInfoA", "lpTitle" );
791  ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
792  "expected '%s' or null, got '%s'\n", selfname, result );
793  okChildInt("StartupInfoA", "dwX", startup.dwX);
794  okChildInt("StartupInfoA", "dwY", startup.dwY);
795  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
796  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
797  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
798  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
799  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
800  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
801  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
802  release_memory();
804 
805  /* not so simplistic now */
806  memset(&startup, 0, sizeof(startup));
807  startup.cb = sizeof(startup);
808  startup.dwFlags = STARTF_USESHOWWINDOW;
809  startup.wShowWindow = SW_SHOWNORMAL;
810  startup.lpTitle = empty;
811  startup.lpDesktop = desktop;
812  startup.dwXCountChars = 0x12121212;
813  startup.dwYCountChars = 0x23232323;
814  startup.dwX = 0x34343434;
815  startup.dwY = 0x45454545;
816  startup.dwXSize = 0x56565656;
817  startup.dwYSize = 0x67676767;
818  startup.dwFillAttribute = 0xA55A;
819 
821  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
822  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
823  /* wait for child to terminate */
824  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
825  /* child process has changed result file, so let profile functions know about it */
827  CloseHandle(info.hThread);
828  CloseHandle(info.hProcess);
829 
830  okChildInt("StartupInfoA", "cb", startup.cb);
831  okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
832  okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
833  okChildInt("StartupInfoA", "dwX", startup.dwX);
834  okChildInt("StartupInfoA", "dwY", startup.dwY);
835  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
836  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
837  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
838  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
839  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
840  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
841  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
842  release_memory();
844 
845  /* not so simplistic now */
846  memset(&startup, 0, sizeof(startup));
847  startup.cb = sizeof(startup);
848  startup.dwFlags = STARTF_USESHOWWINDOW;
849  startup.wShowWindow = SW_SHOWNORMAL;
850  startup.lpTitle = empty;
851  startup.lpDesktop = empty;
852  startup.dwXCountChars = 0x12121212;
853  startup.dwYCountChars = 0x23232323;
854  startup.dwX = 0x34343434;
855  startup.dwY = 0x45454545;
856  startup.dwXSize = 0x56565656;
857  startup.dwYSize = 0x67676767;
858  startup.dwFillAttribute = 0xA55A;
859 
861  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
862  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
863  /* wait for child to terminate */
864  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
865  /* child process has changed result file, so let profile functions know about it */
867  CloseHandle(info.hThread);
868  CloseHandle(info.hProcess);
869 
870  okChildInt("StartupInfoA", "cb", startup.cb);
871  okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
872  okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
873  okChildInt("StartupInfoA", "dwX", startup.dwX);
874  okChildInt("StartupInfoA", "dwY", startup.dwY);
875  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
876  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
877  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
878  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
879  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
880  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
881  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
882  release_memory();
884 
885  /* TODO: test for A/W and W/A and W/W */
886 }
887 
888 static void test_CommandLine(void)
889 {
890  char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
891  char buffer2[MAX_PATH];
894  BOOL ret;
895 
896  memset(&startup, 0, sizeof(startup));
897  startup.cb = sizeof(startup);
898  startup.dwFlags = STARTF_USESHOWWINDOW;
899  startup.wShowWindow = SW_SHOWNORMAL;
900 
901  /* the basics */
903  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
904  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
905  /* wait for child to terminate */
906  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
907  /* child process has changed result file, so let profile functions know about it */
909  CloseHandle(info.hThread);
910  CloseHandle(info.hProcess);
911 
912  okChildInt("Arguments", "argcA", 5);
913  okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
914  okChildString("Arguments", "argvA5", NULL);
915  okChildString("Arguments", "CommandLineA", buffer);
916  release_memory();
918 
919  memset(&startup, 0, sizeof(startup));
920  startup.cb = sizeof(startup);
921  startup.dwFlags = STARTF_USESHOWWINDOW;
922  startup.wShowWindow = SW_SHOWNORMAL;
923 
924  /* from François */
926  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
927  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
928  /* wait for child to terminate */
929  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
930  /* child process has changed result file, so let profile functions know about it */
932  CloseHandle(info.hThread);
933  CloseHandle(info.hProcess);
934 
935  okChildInt("Arguments", "argcA", 7);
936  okChildString("Arguments", "argvA4", "a\"b\\");
937  okChildString("Arguments", "argvA5", "c\"");
938  okChildString("Arguments", "argvA6", "d");
939  okChildString("Arguments", "argvA7", NULL);
940  okChildString("Arguments", "CommandLineA", buffer);
941  release_memory();
943 
944  /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
946  /* Use exename to avoid buffer containing things like 'C:' */
947  sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
948  SetLastError(0xdeadbeef);
950  ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
951  /* wait for child to terminate */
952  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
953  /* child process has changed result file, so let profile functions know about it */
955  CloseHandle(info.hThread);
956  CloseHandle(info.hProcess);
957  sprintf(buffer, "./%s", exename);
958  okChildString("Arguments", "argvA0", buffer);
959  release_memory();
961 
963  /* Use exename to avoid buffer containing things like 'C:' */
964  sprintf(buffer, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
965  SetLastError(0xdeadbeef);
967  ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
968  /* wait for child to terminate */
969  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
970  /* child process has changed result file, so let profile functions know about it */
972  CloseHandle(info.hThread);
973  CloseHandle(info.hProcess);
974  sprintf(buffer, ".\\%s", exename);
975  okChildString("Arguments", "argvA0", buffer);
976  release_memory();
978 
981  assert ( lpFilePart != 0);
982  *(lpFilePart -1 ) = 0;
983  p = strrchr(fullpath, '\\');
984  /* Use exename to avoid buffer containing things like 'C:' */
985  if (p) sprintf(buffer, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p, exename, resfile);
986  else sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
987  SetLastError(0xdeadbeef);
989  ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
990  /* wait for child to terminate */
991  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
992  /* child process has changed result file, so let profile functions know about it */
994  CloseHandle(info.hThread);
995  CloseHandle(info.hProcess);
996  if (p) sprintf(buffer, "..%s/%s", p, exename);
997  else sprintf(buffer, "./%s", exename);
998  okChildString("Arguments", "argvA0", buffer);
999  release_memory();
1001 
1002  /* Using AppName */
1005  assert ( lpFilePart != 0);
1006  *(lpFilePart -1 ) = 0;
1007  p = strrchr(fullpath, '\\');
1008  /* Use exename to avoid buffer containing things like 'C:' */
1009  if (p) sprintf(buffer, "..%s/%s", p, exename);
1010  else sprintf(buffer, "./%s", exename);
1011  sprintf(buffer2, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile);
1012  SetLastError(0xdeadbeef);
1013  ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1014  ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
1015  /* wait for child to terminate */
1016  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1017  /* child process has changed result file, so let profile functions know about it */
1019  CloseHandle(info.hThread);
1020  CloseHandle(info.hProcess);
1021  sprintf(buffer, "tests/process.c dump %s", resfile);
1022  okChildString("Arguments", "argvA0", "dummy");
1023  okChildString("Arguments", "CommandLineA", buffer2);
1024  okChildStringWA("Arguments", "CommandLineW", buffer2);
1025  release_memory();
1027 
1028  if (0) /* Test crashes on NT-based Windows. */
1029  {
1030  /* Test NULL application name and command line parameters. */
1031  SetLastError(0xdeadbeef);
1033  ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1035  "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1036  }
1037 
1038  buffer[0] = '\0';
1039 
1040  /* Test empty application name parameter. */
1041  SetLastError(0xdeadbeef);
1043  ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1045  broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1046  broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1047  "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1048 
1049  buffer2[0] = '\0';
1050 
1051  /* Test empty application name and command line parameters. */
1052  SetLastError(0xdeadbeef);
1053  ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1054  ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1056  broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1057  broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1058  "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1059 
1060  /* Test empty command line parameter. */
1061  SetLastError(0xdeadbeef);
1062  ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1063  ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1065  GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ ||
1066  GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ ||
1067  GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */,
1068  "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1069 
1070  strcpy(buffer, "doesnotexist.exe");
1071  strcpy(buffer2, "does not exist.exe");
1072 
1073  /* Test nonexistent application name. */
1074  SetLastError(0xdeadbeef);
1076  ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1077  ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1078 
1079  SetLastError(0xdeadbeef);
1080  ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1081  ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1082  ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1083 
1084  /* Test nonexistent command line parameter. */
1085  SetLastError(0xdeadbeef);
1087  ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1088  ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1089 
1090  SetLastError(0xdeadbeef);
1091  ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1092  ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1093  ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1094 }
1095 
1096 static void test_Directory(void)
1097 {
1098  char buffer[MAX_PATH];
1101  char windir[MAX_PATH];
1102  static CHAR cmdline[] = "winver.exe";
1103 
1104  memset(&startup, 0, sizeof(startup));
1105  startup.cb = sizeof(startup);
1106  startup.dwFlags = STARTF_USESHOWWINDOW;
1107  startup.wShowWindow = SW_SHOWNORMAL;
1108 
1109  /* the basics */
1111  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1112  GetWindowsDirectoryA( windir, sizeof(windir) );
1113  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n");
1114  /* wait for child to terminate */
1115  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1116  /* child process has changed result file, so let profile functions know about it */
1118  CloseHandle(info.hThread);
1119  CloseHandle(info.hProcess);
1120 
1121  okChildIString("Misc", "CurrDirA", windir);
1122  release_memory();
1124 
1125  /* search PATH for the exe if directory is NULL */
1126  ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1127  ok(TerminateProcess(info.hProcess, 0), "Child process termination\n");
1128  CloseHandle(info.hThread);
1129  CloseHandle(info.hProcess);
1130 
1131  /* if any directory is provided, don't search PATH, error on bad directory */
1132  SetLastError(0xdeadbeef);
1133  memset(&info, 0, sizeof(info));
1135  NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n");
1136  ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1137  ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n");
1138 }
1139 
1140 static void test_Toolhelp(void)
1141 {
1142  char buffer[MAX_PATH];
1146  PROCESSENTRY32 pe;
1147  THREADENTRY32 te;
1148  DWORD ret;
1149  int i;
1150 
1151  memset(&startup, 0, sizeof(startup));
1152  startup.cb = sizeof(startup);
1153  startup.dwFlags = STARTF_USESHOWWINDOW;
1154  startup.wShowWindow = SW_SHOWNORMAL;
1155 
1157  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1158  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1159  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1160  CloseHandle(info.hProcess);
1161  CloseHandle(info.hThread);
1162 
1164  okChildInt("Toolhelp", "cntUsage", 0);
1165  okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1166  okChildInt("Toolhelp", "th32ModuleID", 0);
1167  okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1168  /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1169  okChildInt("Toolhelp", "dwFlags", 0);
1170 
1171  release_memory();
1173 
1175  sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile);
1176  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1177  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1178 
1180  ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1182 
1183  CloseHandle(info.hProcess);
1184  CloseHandle(info.hThread);
1185 
1186  for (i = 0; i < 20; i++)
1187  {
1188  SetLastError(0xdeadbeef);
1190  ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError());
1191  if (!process) break;
1193  Sleep(100);
1194  }
1195  /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1196  ok(i < 20 || broken(i == 20), "process object not released\n");
1197 
1198  snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1199  ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1200  memset(&pe, 0, sizeof(pe));
1201  pe.dwSize = sizeof(pe);
1202  if (pProcess32First(snapshot, &pe))
1203  {
1204  while (pe.th32ParentProcessID != info.dwProcessId)
1205  if (!pProcess32Next(snapshot, &pe)) break;
1206  }
1208  ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n");
1209 
1211  ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1212 
1213  snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1214  ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1215  memset(&te, 0, sizeof(te));
1216  te.dwSize = sizeof(te);
1217  if (pThread32First(snapshot, &te))
1218  {
1219  while (te.th32OwnerProcessID != pe.th32ProcessID)
1220  if (!pThread32Next(snapshot, &te)) break;
1221  }
1223  ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1224 
1226  ok(thread != NULL, "OpenThread failed %u\n", GetLastError());
1227  ret = ResumeThread(thread);
1228  ok(ret == 1, "expected 1, got %u\n", ret);
1230 
1231  ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1233 
1235  okChildInt("Toolhelp", "cntUsage", 0);
1236  okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1237  okChildInt("Toolhelp", "th32ModuleID", 0);
1238  okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1239  /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1240  okChildInt("Toolhelp", "dwFlags", 0);
1241 
1242  release_memory();
1244 }
1245 
1246 static BOOL is_str_env_drive_dir(const char* str)
1247 {
1248  return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1249  str[3] == '=' && str[4] == str[1];
1250 }
1251 
1252 /* compared expected child's environment (in gesA) from actual
1253  * environment our child got
1254  */
1255 static void cmpEnvironment(const char* gesA)
1256 {
1257  int i, clen;
1258  const char* ptrA;
1259  char* res;
1260  char key[32];
1261  BOOL found;
1262 
1263  clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1264 
1265  /* now look each parent env in child */
1266  if ((ptrA = gesA) != NULL)
1267  {
1268  while (*ptrA)
1269  {
1270  for (i = 0; i < clen; i++)
1271  {
1272  sprintf(key, "env%d", i);
1273  res = getChildString("EnvironmentA", key);
1274  if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1275  break;
1276  }
1277  found = i < clen;
1278  ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1279 
1280  ptrA += strlen(ptrA) + 1;
1281  release_memory();
1282  }
1283  }
1284  /* and each child env in parent */
1285  for (i = 0; i < clen; i++)
1286  {
1287  sprintf(key, "env%d", i);
1288  res = getChildString("EnvironmentA", key);
1289  if ((ptrA = gesA) != NULL)
1290  {
1291  while (*ptrA)
1292  {
1293  if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1294  break;
1295  ptrA += strlen(ptrA) + 1;
1296  }
1297  if (!*ptrA) ptrA = NULL;
1298  }
1299 
1300  if (!is_str_env_drive_dir(res))
1301  {
1302  found = ptrA != NULL;
1303  ok(found, "Child-env string %s isn't in parent process\n", res);
1304  }
1305  /* else => should also test we get the right per drive default directory here... */
1306  }
1307 }
1308 
1309 static void test_Environment(void)
1310 {
1311  char buffer[MAX_PATH];
1314  char *child_env;
1315  int child_env_len;
1316  char *ptr;
1317  char *ptr2;
1318  char *env;
1319  int slen;
1320 
1321  memset(&startup, 0, sizeof(startup));
1322  startup.cb = sizeof(startup);
1323  startup.dwFlags = STARTF_USESHOWWINDOW;
1324  startup.wShowWindow = SW_SHOWNORMAL;
1325 
1326  /* the basics */
1328  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1329  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1330  /* wait for child to terminate */
1331  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1332  /* child process has changed result file, so let profile functions know about it */
1334 
1337  release_memory();
1339 
1340  memset(&startup, 0, sizeof(startup));
1341  startup.cb = sizeof(startup);
1342  startup.dwFlags = STARTF_USESHOWWINDOW;
1343  startup.wShowWindow = SW_SHOWNORMAL;
1344 
1345  /* the basics */
1347  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1348 
1349  child_env_len = 0;
1350  ptr = env;
1351  while(*ptr)
1352  {
1353  slen = strlen(ptr)+1;
1354  child_env_len += slen;
1355  ptr += slen;
1356  }
1357  /* Add space for additional environment variables */
1358  child_env_len += 256;
1359  child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1360 
1361  ptr = child_env;
1362  sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1363  ptr += strlen(ptr) + 1;
1364  strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1365  ptr += strlen(ptr) + 1;
1366  strcpy(ptr, "FOO=BAR");
1367  ptr += strlen(ptr) + 1;
1368  strcpy(ptr, "BAR=FOOBAR");
1369  ptr += strlen(ptr) + 1;
1370  /* copy all existing variables except:
1371  * - WINELOADER
1372  * - PATH (already set above)
1373  * - the directory definitions (=[A-Z]:=)
1374  */
1375  for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1376  {
1377  if (strncmp(ptr2, "PATH=", 5) != 0 &&
1378  strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1379  !is_str_env_drive_dir(ptr2))
1380  {
1381  strcpy(ptr, ptr2);
1382  ptr += strlen(ptr) + 1;
1383  }
1384  }
1385  *ptr = '\0';
1386  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1387  /* wait for child to terminate */
1388  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1389  /* child process has changed result file, so let profile functions know about it */
1391 
1392  cmpEnvironment(child_env);
1393 
1394  HeapFree(GetProcessHeap(), 0, child_env);
1396  release_memory();
1398 }
1399 
1400 static void test_SuspendFlag(void)
1401 {
1402  char buffer[MAX_PATH];
1405  DWORD exit_status;
1406  char *result;
1407 
1408  /* let's start simplistic */
1409  memset(&startup, 0, sizeof(startup));
1410  startup.cb = sizeof(startup);
1411  startup.dwFlags = STARTF_USESHOWWINDOW;
1412  startup.wShowWindow = SW_SHOWNORMAL;
1413 
1415  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1416  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1417 
1418  ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1419  Sleep(1000);
1420  ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1421  ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1422 
1423  /* wait for child to terminate */
1424  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1425  /* child process has changed result file, so let profile functions know about it */
1427 
1428  GetStartupInfoA(&us);
1429 
1430  okChildInt("StartupInfoA", "cb", startup.cb);
1431  okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1432  result = getChildString( "StartupInfoA", "lpTitle" );
1433  ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1434  "expected '%s' or null, got '%s'\n", selfname, result );
1435  okChildInt("StartupInfoA", "dwX", startup.dwX);
1436  okChildInt("StartupInfoA", "dwY", startup.dwY);
1437  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1438  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1439  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1440  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1441  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1442  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1443  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1444  release_memory();
1446 }
1447 
1448 static void test_DebuggingFlag(void)
1449 {
1450  char buffer[MAX_PATH];
1451  void *processbase = NULL;
1454  DEBUG_EVENT de;
1455  unsigned dbg = 0;
1456  char *result;
1457 
1458  /* let's start simplistic */
1459  memset(&startup, 0, sizeof(startup));
1460  startup.cb = sizeof(startup);
1461  startup.dwFlags = STARTF_USESHOWWINDOW;
1462  startup.wShowWindow = SW_SHOWNORMAL;
1463 
1465  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1466  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1467 
1468  /* get all startup events up to the entry point break exception */
1469  do
1470  {
1471  ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1473  if (!dbg)
1474  {
1476  "first event: %d\n", de.dwDebugEventCode);
1477  processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1478  }
1479  if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1481  de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1483 
1484  ok(dbg, "I have seen a debug event\n");
1485  /* wait for child to terminate */
1486  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1487  /* child process has changed result file, so let profile functions know about it */
1489 
1490  GetStartupInfoA(&us);
1491 
1492  okChildInt("StartupInfoA", "cb", startup.cb);
1493  okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1494  result = getChildString( "StartupInfoA", "lpTitle" );
1495  ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1496  "expected '%s' or null, got '%s'\n", selfname, result );
1497  okChildInt("StartupInfoA", "dwX", startup.dwX);
1498  okChildInt("StartupInfoA", "dwY", startup.dwY);
1499  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1500  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1501  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1502  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1503  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1504  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1505  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1506  release_memory();
1508 }
1509 
1511 {
1512  return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1513 }
1514 
1515 static void test_Console(void)
1516 {
1517  char buffer[MAX_PATH];
1521  CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC;
1522  DWORD modeIn, modeOut, modeInC, modeOutC;
1523  DWORD cpIn, cpOut, cpInC, cpOutC;
1524  DWORD w;
1525  HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1526  const char* msg = "This is a std-handle inheritance test.";
1527  unsigned msg_len;
1528  BOOL run_tests = TRUE;
1529  char *result;
1530 
1531  memset(&startup, 0, sizeof(startup));
1532  startup.cb = sizeof(startup);
1534  startup.wShowWindow = SW_SHOWNORMAL;
1535 
1536  sa.nLength = sizeof(sa);
1537  sa.lpSecurityDescriptor = NULL;
1538  sa.bInheritHandle = TRUE;
1539 
1540  startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1541  startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1542 
1543  /* first, we need to be sure we're attached to a console */
1544  if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1545  {
1546  /* we're not attached to a console, let's do it */
1547  AllocConsole();
1548  startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1549  startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1550  }
1551  /* now verify everything's ok */
1552  ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1553  ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1554  startup.hStdError = startup.hStdOutput;
1555 
1556  ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1557  ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1558  ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1559  cpIn = GetConsoleCP();
1560  cpOut = GetConsoleOutputCP();
1561 
1563  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile);
1564  ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1565 
1566  /* wait for child to terminate */
1567  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1568  /* child process has changed result file, so let profile functions know about it */
1570 
1571  /* now get the modification the child has made, and resets parents expected values */
1572  ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1573  ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1574  ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1575 
1576  SetConsoleMode(startup.hStdInput, modeIn);
1577  SetConsoleMode(startup.hStdOutput, modeOut);
1578 
1579  cpInC = GetConsoleCP();
1580  cpOutC = GetConsoleOutputCP();
1581 
1582  /* Try to set invalid CP */
1583  SetLastError(0xdeadbeef);
1584  ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1587  "GetLastError: expecting %u got %u\n",
1590  run_tests = FALSE;
1591 
1592 
1593  SetLastError(0xdeadbeef);
1594  ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1597  "GetLastError: expecting %u got %u\n",
1599 
1600  SetConsoleCP(cpIn);
1601  SetConsoleOutputCP(cpOut);
1602 
1603  GetStartupInfoA(&us);
1604 
1605  okChildInt("StartupInfoA", "cb", startup.cb);
1606  okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1607  result = getChildString( "StartupInfoA", "lpTitle" );
1608  ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1609  "expected '%s' or null, got '%s'\n", selfname, result );
1610  okChildInt("StartupInfoA", "dwX", startup.dwX);
1611  okChildInt("StartupInfoA", "dwY", startup.dwY);
1612  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1613  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1614  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1615  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1616  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1617  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1618  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1619 
1620  /* check child correctly inherited the console */
1621  okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1622  okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1623  okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1624  okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1625  okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1626  okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1627  okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1628  okChildInt("Console", "Attributes", sbi.wAttributes);
1629  okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1630  okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1631  okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1632  okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1633  okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1634  okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1635  okChildInt("Console", "InputCP", cpIn);
1636  okChildInt("Console", "OutputCP", cpOut);
1637  okChildInt("Console", "InputMode", modeIn);
1638  okChildInt("Console", "OutputMode", modeOut);
1639 
1640  if (run_tests)
1641  {
1642  ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1643  ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1644  }
1645  else
1646  win_skip("Setting the codepage is not implemented\n");
1647 
1648  ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1649  ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1650  trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1651  ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1652 
1653  release_memory();
1655 
1656  ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1658  &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1659  "Duplicating as inheritable child-output pipe\n");
1660  CloseHandle(hChildOut);
1661 
1662  ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1664  &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1665  "Duplicating as inheritable child-input pipe\n");
1666  CloseHandle(hChildIn);
1667 
1668  memset(&startup, 0, sizeof(startup));
1669  startup.cb = sizeof(startup);
1671  startup.wShowWindow = SW_SHOWNORMAL;
1672  startup.hStdInput = hChildInInh;
1673  startup.hStdOutput = hChildOutInh;
1674  startup.hStdError = hChildOutInh;
1675 
1677  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile);
1678  ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1679  ok(CloseHandle(hChildInInh), "Closing handle\n");
1680  ok(CloseHandle(hChildOutInh), "Closing handle\n");
1681 
1682  msg_len = strlen(msg) + 1;
1683  ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1684  ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1685  memset(buffer, 0, sizeof(buffer));
1686  ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1687  ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1688 
1689  /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1690  ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1691 
1692  /* wait for child to terminate */
1693  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1694  /* child process has changed result file, so let profile functions know about it */
1696 
1697  okChildString("StdHandle", "msg", msg);
1698 
1699  release_memory();
1701 }
1702 
1703 static void test_ExitCode(void)
1704 {
1705  char buffer[MAX_PATH];
1708  DWORD code;
1709 
1710  /* let's start simplistic */
1711  memset(&startup, 0, sizeof(startup));
1712  startup.cb = sizeof(startup);
1713  startup.dwFlags = STARTF_USESHOWWINDOW;
1714  startup.wShowWindow = SW_SHOWNORMAL;
1715 
1717  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile);
1718  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1719 
1720  /* wait for child to terminate */
1721  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1722  /* child process has changed result file, so let profile functions know about it */
1724 
1725  ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1726  okChildInt("ExitCode", "value", code);
1727 
1728  release_memory();
1730 }
1731 
1732 static void test_OpenProcess(void)
1733 {
1734  HANDLE hproc;
1735  void *addr1;
1738  BOOL ret;
1739 
1740  /* not exported in all windows versions */
1741  if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1742  win_skip("VirtualAllocEx not found\n");
1743  return;
1744  }
1745 
1746  /* without PROCESS_VM_OPERATION */
1748  ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1749 
1750  SetLastError(0xdeadbeef);
1751  addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1752  ok(!addr1, "VirtualAllocEx should fail\n");
1754  { /* Win9x */
1755  CloseHandle(hproc);
1756  win_skip("VirtualAllocEx not implemented\n");
1757  return;
1758  }
1759  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1760 
1761  read_bytes = 0xdeadbeef;
1762  SetLastError(0xdeadbeef);
1764  ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1765  ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1766 
1767  CloseHandle(hproc);
1768 
1770  ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1771 
1772  addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1773  ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1774 
1775  /* without PROCESS_QUERY_INFORMATION */
1776  SetLastError(0xdeadbeef);
1777  ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1778  "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1779  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1780 
1781  /* without PROCESS_VM_READ */
1782  read_bytes = 0xdeadbeef;
1783  SetLastError(0xdeadbeef);
1784  ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1785  "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1786  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1787  ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1788 
1789  CloseHandle(hproc);
1790 
1792 
1793  memset(&info, 0xcc, sizeof(info));
1794  read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1795  ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1796 
1797  ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1798  ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1799  ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1800  ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1801  ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1802  /* NT reports Protect == 0 for a not committed memory block */
1803  ok(info.Protect == 0 /* NT */ ||
1804  info.Protect == PAGE_NOACCESS, /* Win9x */
1805  "%x != PAGE_NOACCESS\n", info.Protect);
1806  ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1807 
1808  SetLastError(0xdeadbeef);
1809  ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1810  "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1811  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1812 
1813  CloseHandle(hproc);
1814 
1816  if (hproc)
1817  {
1818  SetLastError(0xdeadbeef);
1819  memset(&info, 0xcc, sizeof(info));
1820  read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1821  if (read_bytes) /* win8 */
1822  {
1823  ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1824  ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1825  ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1826  ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1827  ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1828  ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1829  ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
1830  ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1831  }
1832  else /* before win8 */
1833  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1834 
1835  SetLastError(0xdeadbeef);
1836  ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1837  "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1838  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1839 
1840  CloseHandle(hproc);
1841  }
1842 
1843  ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1844 }
1845 
1846 static void test_GetProcessVersion(void)
1847 {
1848  static char cmdline[] = "winver.exe";
1850  STARTUPINFOA si;
1851  DWORD ret;
1852 
1853  SetLastError(0xdeadbeef);
1854  ret = GetProcessVersion(0);
1855  ok(ret, "GetProcessVersion error %u\n", GetLastError());
1856 
1857  SetLastError(0xdeadbeef);
1859  ok(ret, "GetProcessVersion error %u\n", GetLastError());
1860 
1861  memset(&si, 0, sizeof(si));
1862  si.cb = sizeof(si);
1864  si.wShowWindow = SW_HIDE;
1865  SetLastError(0xdeadbeef);
1866  ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1867  ok(ret, "CreateProcess error %u\n", GetLastError());
1868 
1869  SetLastError(0xdeadbeef);
1870  ret = GetProcessVersion(pi.dwProcessId);
1871  ok(ret, "GetProcessVersion error %u\n", GetLastError());
1872 
1873  SetLastError(0xdeadbeef);
1874  ret = TerminateProcess(pi.hProcess, 0);
1875  ok(ret, "TerminateProcess error %u\n", GetLastError());
1876 
1877  CloseHandle(pi.hProcess);
1878  CloseHandle(pi.hThread);
1879 }
1880 
1882 {
1883  DWORD rc;
1885  static const char harddisk[] = "\\Device\\HarddiskVolume";
1886 
1887  if (!pK32GetProcessImageFileNameA)
1888  {
1889  win_skip("K32GetProcessImageFileNameA is unavailable\n");
1890  return;
1891  }
1892 
1893  /* callers must guess the buffer size */
1894  SetLastError(0xdeadbeef);
1895  rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1897  "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError());
1898 
1899  *process = '\0';
1900  rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1902  if (strncmp(process, harddisk, lstrlenA(harddisk)))
1903  {
1904  todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1905  return;
1906  }
1907 
1908  if (!pQueryFullProcessImageNameA)
1909  win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1910  else
1911  {
1912  CHAR image[MAX_PATH];
1913  DWORD length;
1914 
1915  length = sizeof(image);
1916  expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1918  ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1919  }
1920 }
1921 
1923 {
1924 #define INIT_STR "Just some words"
1925  DWORD length, size;
1927 
1928  if (!pQueryFullProcessImageNameA)
1929  {
1930  win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1931  return;
1932  }
1933 
1934  *module = '\0';
1935  SetLastError(0); /* old Windows don't reset it on success */
1936  size = GetModuleFileNameA(NULL, module, sizeof(module));
1937  ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError());
1938 
1939  /* get the buffer length without \0 terminator */
1940  length = sizeof(buf);
1941  expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1943  ok((buf[0] == '\\' && buf[1] == '\\') ||
1944  lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1945 
1946  /* when the buffer is too small
1947  * - function fail with error ERROR_INSUFFICIENT_BUFFER
1948  * - the size variable is not modified
1949  * tested with the biggest too small size
1950  */
1951  size = length;
1952  sprintf(buf,INIT_STR);
1953  expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1957 
1958  /* retest with smaller buffer size
1959  */
1960  size = 4;
1961  sprintf(buf,INIT_STR);
1962  expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1964  expect_eq_d(4, size);
1966 
1967  /* this is a difference between the ascii and the unicode version
1968  * the unicode version crashes when the size is big enough to hold
1969  * the result while the ascii version throws an error
1970  */
1971  size = 1024;
1972  expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1973  expect_eq_d(1024, size);
1975 }
1976 
1978 {
1979  HANDLE hSelf;
1980  WCHAR module_name[1024], device[1024];
1981  WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
1982  WCHAR buf[1024];
1983  DWORD size, len;
1984 
1985  if (!pQueryFullProcessImageNameW)
1986  {
1987  win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1988  return;
1989  }
1990 
1991  ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1992 
1993  /* GetCurrentProcess pseudo-handle */
1994  size = sizeof(buf) / sizeof(buf[0]);
1995  expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
1998 
2000  /* Real handle */
2001  size = sizeof(buf) / sizeof(buf[0]);
2002  expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2005 
2006  /* Buffer too small */
2007  size = lstrlenW(module_name)/2;
2008  lstrcpyW(buf, deviceW);
2009  SetLastError(0xdeadbeef);
2010  expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2011  expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2013  expect_eq_ws_i(deviceW, buf); /* buffer not changed */
2014 
2015  /* Too small - not space for NUL terminator */
2017  SetLastError(0xdeadbeef);
2018  expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2019  expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
2021 
2022  /* NULL buffer */
2023  size = 0;
2024  expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
2025  expect_eq_d(0, size);
2027 
2028  /* Buffer too small */
2029  size = lstrlenW(module_name)/2;
2030  SetLastError(0xdeadbeef);
2032  expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2033  expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2035  expect_eq_ws_i(module_name, buf); /* buffer not changed */
2036 
2037 
2038  /* native path */
2039  size = sizeof(buf) / sizeof(buf[0]);
2040  expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2042  ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2043  ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2044 
2045  module_name[2] = '\0';
2046  *device = '\0';
2047  size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0]));
2048  ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2049  len = lstrlenW(device);
2050  ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2051 
2052  if (size >= lstrlenW(buf))
2053  {
2054  ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2055  }
2056  else
2057  {
2058  ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2059  buf[len] = '\0';
2060  ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2061  ok(lstrcmpiW(module_name+3, buf+len+1) == 0, "expected '%s' to match '%s'\n", wine_dbgstr_w(module_name+3), wine_dbgstr_w(buf+len+1));
2062  }
2063 
2064  CloseHandle(hSelf);
2065 }
2066 
2067 static void test_Handles(void)
2068 {
2070  HANDLE h2, h3;
2071  BOOL ret;
2072  DWORD code;
2073 
2074  ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2075  handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2076  "invalid current process handle %p\n", handle );
2078  ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2079 #ifdef _WIN64
2080  /* truncated handle */
2081  SetLastError( 0xdeadbeef );
2082  handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2084  ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2085  ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2086  /* sign-extended handle */
2087  SetLastError( 0xdeadbeef );
2090  ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2091  /* invalid high-word */
2092  SetLastError( 0xdeadbeef );
2093  handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2095  ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2096  ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2097 #endif
2098 
2100  ok( handle != 0, "handle %p\n", handle );
2106  ok( h2 == 0 ||
2107  broken( h2 == h3) || /* nt4, w2k */
2108  broken( h2 == INVALID_HANDLE_VALUE), /* win9x */
2109  "wrong handle %p/%p\n", h2, h3 );
2111 }
2112 
2113 static void test_IsWow64Process(void)
2114 {
2116  STARTUPINFOA si;
2117  DWORD ret;
2118  BOOL is_wow64;
2119  static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2120  static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2121 
2122  if (!pIsWow64Process)
2123  {
2124  skip("IsWow64Process is not available\n");
2125  return;
2126  }
2127 
2128  memset(&si, 0, sizeof(si));
2129  si.cb = sizeof(si);
2131  si.wShowWindow = SW_HIDE;
2132  ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2133  if (ret)
2134  {
2135  trace("Created process %s\n", cmdline_wow64);
2136  is_wow64 = FALSE;
2137  ret = pIsWow64Process(pi.hProcess, &is_wow64);
2138  ok(ret, "IsWow64Process failed.\n");
2139  ok(is_wow64, "is_wow64 returned FALSE.\n");
2140 
2141  ret = TerminateProcess(pi.hProcess, 0);
2142  ok(ret, "TerminateProcess error\n");
2143 
2144  CloseHandle(pi.hProcess);
2145  CloseHandle(pi.hThread);
2146  }
2147 
2148  memset(&si, 0, sizeof(si));
2149  si.cb = sizeof(si);
2151  si.wShowWindow = SW_HIDE;
2152  ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2153  if (ret)
2154  {
2155  trace("Created process %s\n", cmdline);
2156  is_wow64 = TRUE;
2157  ret = pIsWow64Process(pi.hProcess, &is_wow64);
2158  ok(ret, "IsWow64Process failed.\n");
2159  ok(!is_wow64, "is_wow64 returned TRUE.\n");
2160 
2161  ret = TerminateProcess(pi.hProcess, 0);
2162  ok(ret, "TerminateProcess error\n");
2163 
2164  CloseHandle(pi.hProcess);
2165  CloseHandle(pi.hThread);
2166  }
2167 }
2168 
2169 static void test_SystemInfo(void)
2170 {
2171  SYSTEM_INFO si, nsi;
2172  BOOL is_wow64;
2173 
2174  if (!pGetNativeSystemInfo)
2175  {
2176  win_skip("GetNativeSystemInfo is not available\n");
2177  return;
2178  }
2179 
2180  if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2181 
2182  GetSystemInfo(&si);
2183  pGetNativeSystemInfo(&nsi);
2184  if (is_wow64)
2185  {
2186  if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2187  {
2188  ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2189  "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2190  S(U(nsi)).wProcessorArchitecture);
2192  "Expected PROCESSOR_AMD_X8664, got %d\n",
2193  nsi.dwProcessorType);
2194  }
2195  }
2196  else
2197  {
2198  ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2199  "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2200  S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2202  "Expected no difference for dwProcessorType, got %d and %d\n",
2204  }
2205 }
2206 
2207 static void test_RegistryQuota(void)
2208 {
2209  BOOL ret;
2210  DWORD max_quota, used_quota;
2211 
2212  if (!pGetSystemRegistryQuota)
2213  {
2214  win_skip("GetSystemRegistryQuota is not available\n");
2215  return;
2216  }
2217 
2218  ret = pGetSystemRegistryQuota(NULL, NULL);
2219  ok(ret == TRUE,
2220  "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2221 
2222  ret = pGetSystemRegistryQuota(&max_quota, NULL);
2223  ok(ret == TRUE,
2224  "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2225 
2226  ret = pGetSystemRegistryQuota(NULL, &used_quota);
2227  ok(ret == TRUE,
2228  "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2229 
2230  ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2231  ok(ret == TRUE,
2232  "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2233 }
2234 
2235 static void test_TerminateProcess(void)
2236 {
2237  static char cmdline[] = "winver.exe";
2239  STARTUPINFOA si;
2240  DWORD ret;
2241  HANDLE dummy, thread;
2242 
2243  memset(&si, 0, sizeof(si));
2244  si.cb = sizeof(si);
2245  SetLastError(0xdeadbeef);
2247  ok(ret, "CreateProcess error %u\n", GetLastError());
2248 
2249  SetLastError(0xdeadbeef);
2250  thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2251  ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2252 
2253  /* create a not closed thread handle duplicate in the target process */
2254  SetLastError(0xdeadbeef);
2257  ok(ret, "DuplicateHandle error %u\n", GetLastError());
2258 
2259  SetLastError(0xdeadbeef);
2260  ret = TerminateThread(thread, 0);
2261  ok(ret, "TerminateThread error %u\n", GetLastError());
2263 
2264  SetLastError(0xdeadbeef);
2265  ret = TerminateProcess(pi.hProcess, 0);
2266  ok(ret, "TerminateProcess error %u\n", GetLastError());
2267 
2268  CloseHandle(pi.hProcess);
2269  CloseHandle(pi.hThread);
2270 }
2271 
2272 static void test_DuplicateHandle(void)
2273 {
2274  char path[MAX_PATH], file_name[MAX_PATH];
2275  HANDLE f, fmin, out;
2276  DWORD info;
2277  BOOL r;
2278 
2280  GetCurrentProcess(), &out, 0, FALSE,
2282  ok(r, "DuplicateHandle error %u\n", GetLastError());
2284  ok(r, "GetHandleInformation error %u\n", GetLastError());
2285  ok(info == 0, "info = %x\n", info);
2286  ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2287  CloseHandle(out);
2288 
2290  GetCurrentProcess(), &out, 0, TRUE,
2292  ok(r, "DuplicateHandle error %u\n", GetLastError());
2294  ok(r, "GetHandleInformation error %u\n", GetLastError());
2295  ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2296  ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2297  CloseHandle(out);
2298 
2300  GetTempFileNameA(path, "wt", 0, file_name);
2302  if (f == INVALID_HANDLE_VALUE)
2303  {
2304  ok(0, "could not create %s\n", file_name);
2305  return;
2306  }
2307 
2310  ok(r, "DuplicateHandle error %u\n", GetLastError());
2311  ok(f == out, "f != out\n");
2313  ok(r, "GetHandleInformation error %u\n", GetLastError());
2314  ok(info == 0, "info = %x\n", info);
2315 
2318  ok(r, "DuplicateHandle error %u\n", GetLastError());
2319  ok(f == out, "f != out\n");
2321  ok(r, "GetHandleInformation error %u\n", GetLastError());
2322  ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2323 
2325  ok(r, "SetHandleInformation error %u\n", GetLastError());
2328  ok(r, "DuplicateHandle error %u\n", GetLastError());
2329  ok(f != out, "f == out\n");
2331  ok(r, "GetHandleInformation error %u\n", GetLastError());
2332  ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2334  ok(r, "SetHandleInformation error %u\n", GetLastError());
2335 
2336  /* Test if DuplicateHandle allocates first free handle */
2337  if (f > out)
2338  {
2339  fmin = out;
2340  }
2341  else
2342  {
2343  fmin = f;
2344  f = out;
2345  }
2346  CloseHandle(fmin);
2349  ok(r, "DuplicateHandle error %u\n", GetLastError());
2350  ok(f == out, "f != out\n");
2351  CloseHandle(out);
2353 
2354  f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2355  if (!is_console(f))
2356  {
2357  skip("DuplicateHandle on console handle\n");
2358  CloseHandle(f);
2359  return;
2360  }
2361 
2364  ok(r, "DuplicateHandle error %u\n", GetLastError());
2365  todo_wine ok(f != out, "f == out\n");
2366  CloseHandle(out);
2367 }
2368 
2369 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2370 static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2371 {
2373  ULONG_PTR value;
2374  DWORD key;
2375  BOOL ret;
2376 
2378 
2379  ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
2380  if (ret)
2381  {
2382  ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key);
2383  ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2384  ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2385  }
2386 }
2387 
2388 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2389 static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2390 {
2391  BOOL ret;
2392  char buffer[MAX_PATH];
2393  STARTUPINFOA si = {0};
2394 
2395  sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command);
2396 
2397  ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2398  ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError());
2399 }
2400 
2401 #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
2402 static void _test_assigned_proc(int line, HANDLE job, int expected_count, ...)
2403 {
2404  char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20];
2406  DWORD ret_len, pid;
2407  va_list valist;
2408  int n;
2409  BOOL ret;
2410 
2411  memset(buf, 0, sizeof(buf));
2412  ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2413  ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2414  if (ret)
2415  {
2417  ok_(__FILE__, line)(expected_count == pid_list->NumberOfAssignedProcesses,
2418  "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n",
2421  ok_(__FILE__, line)(expected_count == pid_list->NumberOfProcessIdsInList,
2422  "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n",
2424 
2426  for (n = 0; n < min(expected_count, pid_list->NumberOfProcessIdsInList); ++n)
2427  {
2428  pid = va_arg(valist, DWORD);
2429  ok_(__FILE__, line)(pid == pid_list->ProcessIdList[n],
2430  "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n",
2431  n, pid, pid_list->ProcessIdList[n]);
2432  }
2433  va_end(valist);
2434  }
2435 }
2436 
2437 #define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc)
2438 static void _test_accounting(int line, HANDLE job, int total_proc, int active_proc, int terminated_proc)
2439 {
2440  JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting;
2441  DWORD ret_len;
2442  BOOL ret;
2443 
2444  memset(&basic_accounting, 0, sizeof(basic_accounting));
2445  ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting, sizeof(basic_accounting), &ret_len);
2446  ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2447  if (ret)
2448  {
2449  /* Not going to check process times or page faults */
2450 
2451  todo_wine_if(total_proc)
2452  ok_(__FILE__, line)(total_proc == basic_accounting.TotalProcesses,
2453  "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n",
2454  total_proc, basic_accounting.TotalProcesses);
2455  todo_wine_if(active_proc)
2456  ok_(__FILE__, line)(active_proc == basic_accounting.ActiveProcesses,
2457  "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n",
2458  active_proc, basic_accounting.ActiveProcesses);
2459  ok_(__FILE__, line)(terminated_proc == basic_accounting.TotalTerminatedProcesses,
2460  "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n",
2461  terminated_proc, basic_accounting.TotalTerminatedProcesses);
2462  }
2463 }
2464 
2465 static void test_IsProcessInJob(void)
2466 {
2467  HANDLE job, job2;
2469  BOOL ret, out;
2470  DWORD dwret;
2471 
2472  if (!pIsProcessInJob)
2473  {
2474  win_skip("IsProcessInJob not available.\n");
2475  return;
2476  }
2477 
2478  job = pCreateJobObjectW(NULL, NULL);
2479  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2480 
2481  job2 = pCreateJobObjectW(NULL, NULL);
2482  ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError());
2483 
2484  create_process("wait", &pi);
2485 
2486  out = TRUE;
2487  ret = pIsProcessInJob(pi.hProcess, job, &out);
2488  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2489  ok(!out, "IsProcessInJob returned out=%u\n", out);
2490  test_assigned_proc(job, 0);
2491  test_accounting(job, 0, 0, 0);
2492 
2493  out = TRUE;
2494  ret = pIsProcessInJob(pi.hProcess, job2, &out);
2495  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2496  ok(!out, "IsProcessInJob returned out=%u\n", out);
2497  test_assigned_proc(job2, 0);
2498  test_accounting(job2, 0, 0, 0);
2499 
2500  out = TRUE;
2501  ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2502  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2503  ok(!out, "IsProcessInJob returned out=%u\n", out);
2504 
2505  ret = pAssignProcessToJobObject(job, pi.hProcess);
2506  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2507 
2508  out = FALSE;
2509  ret = pIsProcessInJob(pi.hProcess, job, &out);
2510  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2511  ok(out, "IsProcessInJob returned out=%u\n", out);
2512  test_assigned_proc(job, 1, pi.dwProcessId);
2513  test_accounting(job, 1, 1, 0);
2514 
2515  out = TRUE;
2516  ret = pIsProcessInJob(pi.hProcess, job2, &out);
2517  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2518  ok(!out, "IsProcessInJob returned out=%u\n", out);
2519  test_assigned_proc(job2, 0);
2520  test_accounting(job2, 0, 0, 0);
2521 
2522  out = FALSE;
2523  ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2524  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2525  ok(out, "IsProcessInJob returned out=%u\n", out);
2526 
2527  TerminateProcess(pi.hProcess, 0);
2528 
2529  dwret = WaitForSingleObject(pi.hProcess, 1000);
2530  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2531 
2532  out = FALSE;
2533  ret = pIsProcessInJob(pi.hProcess, job, &out);
2534  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2535  ok(out, "IsProcessInJob returned out=%u\n", out);
2536  test_assigned_proc(job, 0);
2537  test_accounting(job, 1, 0, 0);
2538 
2539  CloseHandle(pi.hProcess);
2540  CloseHandle(pi.hThread);
2541  CloseHandle(job);
2542  CloseHandle(job2);
2543 }
2544 
2545 static void test_TerminateJobObject(void)
2546 {
2547  HANDLE job;
2549  BOOL ret;
2550  DWORD dwret;
2551 
2552  job = pCreateJobObjectW(NULL, NULL);
2553  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2554  test_assigned_proc(job, 0);
2555  test_accounting(job, 0, 0, 0);
2556 
2557  create_process("wait", &pi);
2558 
2559  ret = pAssignProcessToJobObject(job, pi.hProcess);
2560  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2561  test_assigned_proc(job, 1, pi.dwProcessId);
2562  test_accounting(job, 1, 1, 0);
2563 
2564  ret = pTerminateJobObject(job, 123);
2565  ok(ret, "TerminateJobObject error %u\n", GetLastError());
2566 
2567  dwret = WaitForSingleObject(pi.hProcess, 1000);
2568  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2569  if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2570  test_assigned_proc(job, 0);
2571  test_accounting(job, 1, 0, 0);
2572 
2573  ret = GetExitCodeProcess(pi.hProcess, &dwret);
2574  ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
2575  ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
2576  "wrong exitcode %u\n", dwret);
2577 
2578  CloseHandle(pi.hProcess);
2579  CloseHandle(pi.hThread);
2580 
2581  /* Test adding an already terminated process to a job object */
2582  create_process("exit", &pi);
2583 
2584  dwret = WaitForSingleObject(pi.hProcess, 1000);
2585  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2586 
2587  SetLastError(0xdeadbeef);
2588  ret = pAssignProcessToJobObject(job, pi.hProcess);
2589  ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2591  test_assigned_proc(job, 0);
2592  test_accounting(job, 1, 0, 0);
2593 
2594  CloseHandle(pi.hProcess);
2595  CloseHandle(pi.hThread);
2596 
2597  CloseHandle(job);
2598 }
2599 
2601 {
2602  char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2604  JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2605  JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2606  DWORD dwret, ret_len;
2608  HANDLE job;
2609  BOOL ret;
2610 
2611  job = pCreateJobObjectW(NULL, NULL);
2612  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2613 
2614  /* Only active processes are returned */
2615  create_process("exit", &pi[0]);
2616  ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2617  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2618  dwret = WaitForSingleObject(pi[0].hProcess, 1000);
2619  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2620 
2621  CloseHandle(pi[0].hProcess);
2622  CloseHandle(pi[0].hThread);
2623 
2624  create_process("wait", &pi[0]);
2625  ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2626  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2627 
2628  create_process("wait", &pi[1]);
2629  ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2630  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2631 
2632  SetLastError(0xdeadbeef);
2635  ok(!ret, "QueryInformationJobObject expected failure\n");
2637 
2638  SetLastError(0xdeadbeef);
2639  memset(buf, 0, sizeof(buf));
2640  pid_list->NumberOfAssignedProcesses = 42;
2641  pid_list->NumberOfProcessIdsInList = 42;
2644  todo_wine
2645  ok(!ret, "QueryInformationJobObject expected failure\n");
2646  todo_wine
2648  if (ret)
2649  {
2650  todo_wine
2651  expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2652  todo_wine
2653  expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2654  }
2655 
2656  memset(buf, 0, sizeof(buf));
2657  ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2658  ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2659  if(ret)
2660  {
2661  if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2662  win_skip("Number of assigned processes broken on Win 8\n");
2663  else
2664  {
2665  ULONG_PTR *list = pid_list->ProcessIdList;
2666 
2667  todo_wine
2669  "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2670 
2671  todo_wine
2672  expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2673  todo_wine
2674  expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2675  todo_wine
2676  expect_eq_d(pi[0].dwProcessId, list[0]);
2677  todo_wine
2678  expect_eq_d(pi[1].dwProcessId, list[1]);
2679  }
2680  }
2681 
2682  /* test JobObjectBasicLimitInformation */
2683  ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2684  sizeof(*basic_limit_info) - 1, &ret_len);
2685  ok(!ret, "QueryInformationJobObject expected failure\n");
2687 
2688  ret_len = 0xdeadbeef;
2689  memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2690  ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2691  sizeof(*basic_limit_info), &ret_len);
2692  ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2693  ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2694  expect_eq_d(0, basic_limit_info->LimitFlags);
2695 
2696  /* test JobObjectExtendedLimitInformation */
2697  ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2698  sizeof(ext_limit_info) - 1, &ret_len);
2699  ok(!ret, "QueryInformationJobObject expected failure\n");
2701 
2702  ret_len = 0xdeadbeef;
2703  memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2704  ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2705  sizeof(ext_limit_info), &ret_len);
2706  ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2707  ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2708  expect_eq_d(0, basic_limit_info->LimitFlags);
2709 
2710  TerminateProcess(pi[0].hProcess, 0);
2711  CloseHandle(pi[0].hProcess);
2712  CloseHandle(pi[0].hThread);
2713 
2714  TerminateProcess(pi[1].hProcess, 0);
2715  CloseHandle(pi[1].hProcess);
2716  CloseHandle(pi[1].hThread);
2717 
2718  CloseHandle(job);
2719 }
2720 
2721 static void test_CompletionPort(void)
2722 {
2725  HANDLE job, port;
2726  DWORD dwret;
2727  BOOL ret;
2728 
2729  job = pCreateJobObjectW(NULL, NULL);
2730  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2731 
2732  port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2733  ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
2734 
2735  port_info.CompletionKey = job;
2736  port_info.CompletionPort = port;
2737  ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2738  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2739 
2740  create_process("wait", &pi);
2741 
2742  ret = pAssignProcessToJobObject(job, pi.hProcess);
2743  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2744 
2746 
2747  TerminateProcess(pi.hProcess, 0);
2748  dwret = WaitForSingleObject(pi.hProcess, 1000);
2749  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2750 
2753 
2754  CloseHandle(pi.hProcess);
2755  CloseHandle(pi.hThread);
2756  CloseHandle(job);
2757  CloseHandle(port);
2758 }
2759 
2760 static void test_KillOnJobClose(void)
2761 {
2764  DWORD dwret;
2765  HANDLE job;
2766  BOOL ret;
2767 
2768  job = pCreateJobObjectW(NULL, NULL);
2769  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2770 
2772  ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2774  {
2775  win_skip("Kill on job close limit not available\n");
2776  return;
2777  }
2778  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2779  test_assigned_proc(job, 0);
2780  test_accounting(job, 0, 0, 0);
2781 
2782  create_process("wait", &pi);
2783 
2784  ret = pAssignProcessToJobObject(job, pi.hProcess);
2785  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2786  test_assigned_proc(job, 1, pi.dwProcessId);
2787  test_accounting(job, 1, 1, 0);
2788 
2789  CloseHandle(job);
2790 
2791  dwret = WaitForSingleObject(pi.hProcess, 1000);
2792  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2793  if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2794 
2795  CloseHandle(pi.hProcess);
2796  CloseHandle(pi.hThread);
2797 }
2798 
2799 static void test_WaitForJobObject(void)
2800 {
2801  HANDLE job;
2803  BOOL ret;
2804  DWORD dwret;
2805 
2806  /* test waiting for a job object when the process is killed */
2807  job = pCreateJobObjectW(NULL, NULL);
2808  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2809 
2810  dwret = WaitForSingleObject(job, 100);
2811  ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2812 
2813  create_process("wait", &pi);
2814 
2815  ret = pAssignProcessToJobObject(job, pi.hProcess);
2816  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2817 
2818  dwret = WaitForSingleObject(job, 100);
2819  ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2820 
2821  ret = pTerminateJobObject(job, 123);
2822  ok(ret, "TerminateJobObject error %u\n", GetLastError());
2823 
2824  dwret = WaitForSingleObject(job, 500);
2825  ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2826  "WaitForSingleObject returned %u\n", dwret);
2827 
2828  if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2829  {
2830 #ifdef __REACTOS__
2831  if (!ret)
2832  {
2833  ok(0, "HACK: Killing process to speed up the test\n");
2834  TerminateProcess(pi.hProcess, 0);
2835  }
2836 #endif
2837  CloseHandle(pi.hProcess);
2838  CloseHandle(pi.hThread);
2839  CloseHandle(job);
2840  win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2841  return;
2842  }
2843 
2844  /* the object is not reset immediately */
2845  dwret = WaitForSingleObject(job, 100);
2846  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2847 
2848  CloseHandle(pi.hProcess);
2849  CloseHandle(pi.hThread);
2850 
2851  /* creating a new process doesn't reset the signalled state */
2852  create_process("wait", &pi);
2853 
2854  ret = pAssignProcessToJobObject(job, pi.hProcess);
2855  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2856 
2857  dwret = WaitForSingleObject(job, 100);
2858  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2859 
2860  ret = pTerminateJobObject(job, 123);
2861  ok(ret, "TerminateJobObject error %u\n", GetLastError());
2862 
2863  CloseHandle(pi.hProcess);
2864  CloseHandle(pi.hThread);
2865 
2866  CloseHandle(job);
2867 
2868  /* repeat the test, but this time the process terminates properly */
2869  job = pCreateJobObjectW(NULL, NULL);
2870  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2871 
2872  dwret = WaitForSingleObject(job, 100);
2873  ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2874 
2875  create_process("exit", &pi);
2876 
2877  ret = pAssignProcessToJobObject(job, pi.hProcess);
2878  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2879 
2880  dwret = WaitForSingleObject(job, 100);
2881  ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2882 
2883  CloseHandle(pi.hProcess);
2884  CloseHandle(pi.hThread);
2885  CloseHandle(job);
2886 }
2887 
2889 {
2890  HANDLE job;
2891  BOOL ret;
2892 
2893  job = pCreateJobObjectW(NULL, NULL);
2894  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2895 
2896  ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2897  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2899  test_accounting(job, 1, 1, 0);
2900 
2901  return job;
2902 }
2903 
2905 {
2906  char buffer[MAX_PATH];
2908  STARTUPINFOA si = {0};
2909  DWORD dwret;
2910  BOOL ret, out;
2911 
2912  if (!pIsProcessInJob)
2913  {
2914  win_skip("IsProcessInJob not available.\n");
2915  return;
2916  }
2917 
2918  sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2919 
2920  ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2921  ok(ret, "CreateProcessA error %u\n", GetLastError());
2922 
2923  out = FALSE;
2924  ret = pIsProcessInJob(pi.hProcess, job, &out);
2925  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2926  ok(out, "IsProcessInJob returned out=%u\n", out);
2927  test_assigned_proc(job, 2, GetCurrentProcessId(), pi.dwProcessId);
2928  test_accounting(job, 2, 2, 0);
2929 
2930  dwret = WaitForSingleObject(pi.hProcess, 1000);
2931  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2932 
2933  CloseHandle(pi.hProcess);
2934  CloseHandle(pi.hThread);
2935 }
2936 
2938 {
2941  STARTUPINFOA si = {0};
2942  char buffer[MAX_PATH];
2943  BOOL ret, out;
2944  DWORD dwret;
2945 
2946  if (!pIsProcessInJob)
2947  {
2948  win_skip("IsProcessInJob not available.\n");
2949  return;
2950  }
2951 
2952  sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2953 
2955  ok(!ret, "CreateProcessA expected failure\n");
2958  test_accounting(job, 2, 1, 0);
2959 
2960  if (ret)
2961  {
2962  TerminateProcess(pi.hProcess, 0);
2963 
2964  dwret = WaitForSingleObject(pi.hProcess, 1000);
2965  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2966 
2967  CloseHandle(pi.hProcess);
2968  CloseHandle(pi.hThread);
2969  }
2970 
2972  ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2973  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2974 
2976  ok(ret, "CreateProcessA error %u\n", GetLastError());
2977 
2978  ret = pIsProcessInJob(pi.hProcess, job, &out);
2979  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2980  ok(!out, "IsProcessInJob returned out=%u\n", out);
2982  test_accounting(job, 2, 1, 0);
2983 
2984  dwret = WaitForSingleObject(pi.hProcess, 1000);
2985  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2986 
2987  CloseHandle(pi.hProcess);
2988  CloseHandle(pi.hThread);
2989 
2991  ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2992  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2993 
2994  ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2995  ok(ret, "CreateProcess error %u\n", GetLastError());
2996 
2997  ret = pIsProcessInJob(pi.hProcess, job, &out);
2998  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2999  ok(!out, "IsProcessInJob returned out=%u\n", out);
3001  test_accounting(job, 2, 1, 0);
3002 
3003  dwret = WaitForSingleObject(pi.hProcess, 1000);
3004  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
3005 
3006  CloseHandle(pi.hProcess);
3007  CloseHandle(pi.hThread);
3008 
3009  /* unset breakaway ok */
3010  limit_info.BasicLimitInformation.LimitFlags = 0;
3011  ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3012  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
3013 }
3014 
3015 static void test_StartupNoConsole(void)
3016 {
3017 #ifndef _WIN64
3018  char buffer[MAX_PATH];
3021 
3022  memset(&startup, 0, sizeof(startup));
3023  startup.cb = sizeof(startup);
3024  startup.dwFlags = STARTF_USESHOWWINDOW;
3025  startup.wShowWindow = SW_SHOWNORMAL;
3027  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3029  &info), "CreateProcess\n");
3030  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3032  okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3033  okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3034  okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3035  okChildInt("TEB", "hStdInput", 0);
3036  okChildInt("TEB", "hStdOutput", 0);
3037  okChildInt("TEB", "hStdError", 0);
3038  release_memory();
3040 #endif
3041 }
3042 
3043 static void test_DetachConsoleHandles(void)
3044 {
3045 #ifndef _WIN64
3046  char buffer[MAX_PATH];
3049  UINT result;
3050 
3051  memset(&startup, 0, sizeof(startup));
3052  startup.cb = sizeof(startup);
3054  startup.wShowWindow = SW_SHOWNORMAL;
3055  startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
3056  startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
3057  startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
3059  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3061  &info), "CreateProcess\n");
3062  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3064 
3065  result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile);
3066  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3067  result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile);
3068  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3069  result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile);
3070  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3071  result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile);
3072  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3073  result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile);
3074  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3075  result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile);
3076  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3077 
3078  release_memory();
3080 #endif
3081 }
3082 
3083 #if defined(__i386__) || defined(__x86_64__)
3084 static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi,
3086 {
3088 
3089  if (!ReadProcessMemory(process_handle, mbi->BaseAddress, &dos_header, sizeof(dos_header), NULL))
3090  return FALSE;
3091 
3093  ((ULONG)dos_header.e_lfanew > mbi->RegionSize) ||
3094  (dos_header.e_lfanew < sizeof(dos_header)))
3095  return FALSE;
3096 
3097  if (!ReadProcessMemory(process_handle, (char *)mbi->BaseAddress + dos_header.e_lfanew,
3098  nt_header, sizeof(*nt_header), NULL))
3099  return FALSE;
3100 
3101  return (nt_header->Signature == IMAGE_NT_SIGNATURE);
3102 }
3103 
3104 static PVOID get_process_exe(HANDLE process_handle, IMAGE_NT_HEADERS *nt_header)
3105 {
3106  PVOID exe_base, address;
3108 
3109  /* Find the EXE base in the new process */
3110  exe_base = NULL;
3111  for (address = NULL ;
3112  VirtualQueryEx(process_handle, address, &mbi, sizeof(mbi)) ;
3113  address = (char *)mbi.BaseAddress + mbi.RegionSize) {
3114  if ((mbi.Type == SEC_IMAGE) &&
3115  read_nt_header(process_handle, &mbi, nt_header) &&
3117  exe_base = mbi.BaseAddress;
3118  break;
3119  }
3120  }
3121 
3122  return exe_base;
3123 }
3124 
3125 static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE_NT_HEADERS *nt_header)
3126 {
3127  BOOL ret;
3129  ULONG_PTR orig_iat_entry_value, iat_entry_value;
3130 
3132  ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, "Import table Size is zero\n");
3133 
3136  return FALSE;
3137 
3138  /* Read the first IID */
3139  ret = ReadProcessMe