ReactOS  0.4.15-dev-3303-g1ade494
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 #if defined(__REACTOS__) && defined(_M_AMD64)
1152  if (!winetest_interactive)
1153  {
1154  skip("ROSTESTS-372: Skipping test in kernel32_winetest:process test_Toolhelp because it leaves a process behind on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
1155  //return;
1156  }
1157 #endif
1158 
1159  memset(&startup, 0, sizeof(startup));
1160  startup.cb = sizeof(startup);
1161  startup.dwFlags = STARTF_USESHOWWINDOW;
1162  startup.wShowWindow = SW_SHOWNORMAL;
1163 
1165  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1166  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1167  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1168  CloseHandle(info.hProcess);
1169  CloseHandle(info.hThread);
1170 
1172  okChildInt("Toolhelp", "cntUsage", 0);
1173  okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1174  okChildInt("Toolhelp", "th32ModuleID", 0);
1175  okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1176  /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1177  okChildInt("Toolhelp", "dwFlags", 0);
1178 
1179  release_memory();
1181 
1182 #if defined(__REACTOS__) && defined(_M_AMD64)
1183  if (!winetest_interactive)
1184  {
1185  skip("ROSTESTS-371: Skipping kernel32_winetest:sync test_apc_deadlock because it fails on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
1186  }
1187  else
1188  {
1189 #endif
1190 
1192  sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile);
1193  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1194  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1195 
1197  ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1199 
1200  CloseHandle(info.hProcess);
1201  CloseHandle(info.hThread);
1202 #if defined(__REACTOS__) && defined(_M_AMD64)
1203  }
1204 #endif
1205 
1206  for (i = 0; i < 20; i++)
1207  {
1208  SetLastError(0xdeadbeef);
1210  ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError());
1211  if (!process) break;
1213  Sleep(100);
1214  }
1215  /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1216  ok(i < 20 || broken(i == 20), "process object not released\n");
1217 
1218  snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1219  ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1220  memset(&pe, 0, sizeof(pe));
1221  pe.dwSize = sizeof(pe);
1222  if (pProcess32First(snapshot, &pe))
1223  {
1224  while (pe.th32ParentProcessID != info.dwProcessId)
1225  if (!pProcess32Next(snapshot, &pe)) break;
1226  }
1228  ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n");
1229 
1231  ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1232 
1233  snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1234  ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1235  memset(&te, 0, sizeof(te));
1236  te.dwSize = sizeof(te);
1237  if (pThread32First(snapshot, &te))
1238  {
1239  while (te.th32OwnerProcessID != pe.th32ProcessID)
1240  if (!pThread32Next(snapshot, &te)) break;
1241  }
1243  ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1244 
1246  ok(thread != NULL, "OpenThread failed %u\n", GetLastError());
1247  ret = ResumeThread(thread);
1248  ok(ret == 1, "expected 1, got %u\n", ret);
1250 
1251  ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1253 
1255  okChildInt("Toolhelp", "cntUsage", 0);
1256  okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1257  okChildInt("Toolhelp", "th32ModuleID", 0);
1258  okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1259  /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1260  okChildInt("Toolhelp", "dwFlags", 0);
1261 
1262  release_memory();
1264 }
1265 
1266 static BOOL is_str_env_drive_dir(const char* str)
1267 {
1268  return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1269  str[3] == '=' && str[4] == str[1];
1270 }
1271 
1272 /* compared expected child's environment (in gesA) from actual
1273  * environment our child got
1274  */
1275 static void cmpEnvironment(const char* gesA)
1276 {
1277  int i, clen;
1278  const char* ptrA;
1279  char* res;
1280  char key[32];
1281  BOOL found;
1282 
1283  clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1284 
1285  /* now look each parent env in child */
1286  if ((ptrA = gesA) != NULL)
1287  {
1288  while (*ptrA)
1289  {
1290  for (i = 0; i < clen; i++)
1291  {
1292  sprintf(key, "env%d", i);
1293  res = getChildString("EnvironmentA", key);
1294  if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1295  break;
1296  }
1297  found = i < clen;
1298  ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1299 
1300  ptrA += strlen(ptrA) + 1;
1301  release_memory();
1302  }
1303  }
1304  /* and each child env in parent */
1305  for (i = 0; i < clen; i++)
1306  {
1307  sprintf(key, "env%d", i);
1308  res = getChildString("EnvironmentA", key);
1309  if ((ptrA = gesA) != NULL)
1310  {
1311  while (*ptrA)
1312  {
1313  if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1314  break;
1315  ptrA += strlen(ptrA) + 1;
1316  }
1317  if (!*ptrA) ptrA = NULL;
1318  }
1319 
1320  if (!is_str_env_drive_dir(res))
1321  {
1322  found = ptrA != NULL;
1323  ok(found, "Child-env string %s isn't in parent process\n", res);
1324  }
1325  /* else => should also test we get the right per drive default directory here... */
1326  }
1327 }
1328 
1329 static void test_Environment(void)
1330 {
1331  char buffer[MAX_PATH];
1334  char *child_env;
1335  int child_env_len;
1336  char *ptr;
1337  char *ptr2;
1338  char *env;
1339  int slen;
1340 
1341  memset(&startup, 0, sizeof(startup));
1342  startup.cb = sizeof(startup);
1343  startup.dwFlags = STARTF_USESHOWWINDOW;
1344  startup.wShowWindow = SW_SHOWNORMAL;
1345 
1346  /* the basics */
1348  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1349  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1350  /* wait for child to terminate */
1351  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1352  /* child process has changed result file, so let profile functions know about it */
1354 
1357  release_memory();
1359 
1360  memset(&startup, 0, sizeof(startup));
1361  startup.cb = sizeof(startup);
1362  startup.dwFlags = STARTF_USESHOWWINDOW;
1363  startup.wShowWindow = SW_SHOWNORMAL;
1364 
1365  /* the basics */
1367  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1368 
1369  child_env_len = 0;
1370  ptr = env;
1371  while(*ptr)
1372  {
1373  slen = strlen(ptr)+1;
1374  child_env_len += slen;
1375  ptr += slen;
1376  }
1377  /* Add space for additional environment variables */
1378  child_env_len += 256;
1379  child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1380 
1381  ptr = child_env;
1382  sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1383  ptr += strlen(ptr) + 1;
1384  strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1385  ptr += strlen(ptr) + 1;
1386  strcpy(ptr, "FOO=BAR");
1387  ptr += strlen(ptr) + 1;
1388  strcpy(ptr, "BAR=FOOBAR");
1389  ptr += strlen(ptr) + 1;
1390  /* copy all existing variables except:
1391  * - WINELOADER
1392  * - PATH (already set above)
1393  * - the directory definitions (=[A-Z]:=)
1394  */
1395  for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1396  {
1397  if (strncmp(ptr2, "PATH=", 5) != 0 &&
1398  strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1399  !is_str_env_drive_dir(ptr2))
1400  {
1401  strcpy(ptr, ptr2);
1402  ptr += strlen(ptr) + 1;
1403  }
1404  }
1405  *ptr = '\0';
1406  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1407  /* wait for child to terminate */
1408  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1409  /* child process has changed result file, so let profile functions know about it */
1411 
1412  cmpEnvironment(child_env);
1413 
1414  HeapFree(GetProcessHeap(), 0, child_env);
1416  release_memory();
1418 }
1419 
1420 static void test_SuspendFlag(void)
1421 {
1422  char buffer[MAX_PATH];
1425  DWORD exit_status;
1426  char *result;
1427 
1428  /* let's start simplistic */
1429  memset(&startup, 0, sizeof(startup));
1430  startup.cb = sizeof(startup);
1431  startup.dwFlags = STARTF_USESHOWWINDOW;
1432  startup.wShowWindow = SW_SHOWNORMAL;
1433 
1435  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1436  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1437 
1438  ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1439  Sleep(1000);
1440  ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1441  ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1442 
1443  /* wait for child to terminate */
1444  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1445  /* child process has changed result file, so let profile functions know about it */
1447 
1448  GetStartupInfoA(&us);
1449 
1450  okChildInt("StartupInfoA", "cb", startup.cb);
1451  okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1452  result = getChildString( "StartupInfoA", "lpTitle" );
1453  ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1454  "expected '%s' or null, got '%s'\n", selfname, result );
1455  okChildInt("StartupInfoA", "dwX", startup.dwX);
1456  okChildInt("StartupInfoA", "dwY", startup.dwY);
1457  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1458  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1459  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1460  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1461  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1462  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1463  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1464  release_memory();
1466 }
1467 
1468 static void test_DebuggingFlag(void)
1469 {
1470  char buffer[MAX_PATH];
1471  void *processbase = NULL;
1474  DEBUG_EVENT de;
1475  unsigned dbg = 0;
1476  char *result;
1477 
1478  /* let's start simplistic */
1479  memset(&startup, 0, sizeof(startup));
1480  startup.cb = sizeof(startup);
1481  startup.dwFlags = STARTF_USESHOWWINDOW;
1482  startup.wShowWindow = SW_SHOWNORMAL;
1483 
1485  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1486  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1487 
1488  /* get all startup events up to the entry point break exception */
1489  do
1490  {
1491  ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1493  if (!dbg)
1494  {
1496  "first event: %d\n", de.dwDebugEventCode);
1497  processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1498  }
1499  if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1501  de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1503 
1504  ok(dbg, "I have seen a debug event\n");
1505  /* wait for child to terminate */
1506  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1507  /* child process has changed result file, so let profile functions know about it */
1509 
1510  GetStartupInfoA(&us);
1511 
1512  okChildInt("StartupInfoA", "cb", startup.cb);
1513  okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1514  result = getChildString( "StartupInfoA", "lpTitle" );
1515  ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1516  "expected '%s' or null, got '%s'\n", selfname, result );
1517  okChildInt("StartupInfoA", "dwX", startup.dwX);
1518  okChildInt("StartupInfoA", "dwY", startup.dwY);
1519  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1520  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1521  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1522  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1523  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1524  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1525  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1526  release_memory();
1528 }
1529 
1531 {
1532  return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1533 }
1534 
1535 static void test_Console(void)
1536 {
1537  char buffer[MAX_PATH];
1541  CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC;
1542  DWORD modeIn, modeOut, modeInC, modeOutC;
1543  DWORD cpIn, cpOut, cpInC, cpOutC;
1544  DWORD w;
1545  HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1546  const char* msg = "This is a std-handle inheritance test.";
1547  unsigned msg_len;
1548  BOOL run_tests = TRUE;
1549  char *result;
1550 
1551  memset(&startup, 0, sizeof(startup));
1552  startup.cb = sizeof(startup);
1554  startup.wShowWindow = SW_SHOWNORMAL;
1555 
1556  sa.nLength = sizeof(sa);
1557  sa.lpSecurityDescriptor = NULL;
1558  sa.bInheritHandle = TRUE;
1559 
1560  startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1561  startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1562 
1563  /* first, we need to be sure we're attached to a console */
1564  if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1565  {
1566  /* we're not attached to a console, let's do it */
1567  AllocConsole();
1568  startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1569  startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1570  }
1571  /* now verify everything's ok */
1572  ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1573  ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1574  startup.hStdError = startup.hStdOutput;
1575 
1576  ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1577  ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1578  ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1579  cpIn = GetConsoleCP();
1580  cpOut = GetConsoleOutputCP();
1581 
1583  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile);
1584  ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1585 
1586  /* wait for child to terminate */
1587  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1588  /* child process has changed result file, so let profile functions know about it */
1590 
1591  /* now get the modification the child has made, and resets parents expected values */
1592  ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1593  ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1594  ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1595 
1596  SetConsoleMode(startup.hStdInput, modeIn);
1597  SetConsoleMode(startup.hStdOutput, modeOut);
1598 
1599  cpInC = GetConsoleCP();
1600  cpOutC = GetConsoleOutputCP();
1601 
1602  /* Try to set invalid CP */
1603  SetLastError(0xdeadbeef);
1604  ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1607  "GetLastError: expecting %u got %u\n",
1610  run_tests = FALSE;
1611 
1612 
1613  SetLastError(0xdeadbeef);
1614  ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1617  "GetLastError: expecting %u got %u\n",
1619 
1620  SetConsoleCP(cpIn);
1621  SetConsoleOutputCP(cpOut);
1622 
1623  GetStartupInfoA(&us);
1624 
1625  okChildInt("StartupInfoA", "cb", startup.cb);
1626  okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1627  result = getChildString( "StartupInfoA", "lpTitle" );
1628  ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1629  "expected '%s' or null, got '%s'\n", selfname, result );
1630  okChildInt("StartupInfoA", "dwX", startup.dwX);
1631  okChildInt("StartupInfoA", "dwY", startup.dwY);
1632  okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1633  okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1634  okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1635  okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1636  okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1637  okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1638  okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1639 
1640  /* check child correctly inherited the console */
1641  okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1642  okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1643  okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1644  okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1645  okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1646  okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1647  okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1648  okChildInt("Console", "Attributes", sbi.wAttributes);
1649  okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1650  okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1651  okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1652  okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1653  okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1654  okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1655  okChildInt("Console", "InputCP", cpIn);
1656  okChildInt("Console", "OutputCP", cpOut);
1657  okChildInt("Console", "InputMode", modeIn);
1658  okChildInt("Console", "OutputMode", modeOut);
1659 
1660  if (run_tests)
1661  {
1662  ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1663  ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1664  }
1665  else
1666  win_skip("Setting the codepage is not implemented\n");
1667 
1668  ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1669  ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1670  trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1671  ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1672 
1673  release_memory();
1675 
1676  ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1678  &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1679  "Duplicating as inheritable child-output pipe\n");
1680  CloseHandle(hChildOut);
1681 
1682  ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1684  &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1685  "Duplicating as inheritable child-input pipe\n");
1686  CloseHandle(hChildIn);
1687 
1688  memset(&startup, 0, sizeof(startup));
1689  startup.cb = sizeof(startup);
1691  startup.wShowWindow = SW_SHOWNORMAL;
1692  startup.hStdInput = hChildInInh;
1693  startup.hStdOutput = hChildOutInh;
1694  startup.hStdError = hChildOutInh;
1695 
1697  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile);
1698  ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1699  ok(CloseHandle(hChildInInh), "Closing handle\n");
1700  ok(CloseHandle(hChildOutInh), "Closing handle\n");
1701 
1702  msg_len = strlen(msg) + 1;
1703  ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1704  ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1705  memset(buffer, 0, sizeof(buffer));
1706  ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1707  ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1708 
1709  /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1710  ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1711 
1712  /* wait for child to terminate */
1713  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1714  /* child process has changed result file, so let profile functions know about it */
1716 
1717  okChildString("StdHandle", "msg", msg);
1718 
1719  release_memory();
1721 }
1722 
1723 static void test_ExitCode(void)
1724 {
1725  char buffer[MAX_PATH];
1728  DWORD code;
1729 
1730  /* let's start simplistic */
1731  memset(&startup, 0, sizeof(startup));
1732  startup.cb = sizeof(startup);
1733  startup.dwFlags = STARTF_USESHOWWINDOW;
1734  startup.wShowWindow = SW_SHOWNORMAL;
1735 
1737  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile);
1738  ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1739 
1740  /* wait for child to terminate */
1741  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1742  /* child process has changed result file, so let profile functions know about it */
1744 
1745  ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1746  okChildInt("ExitCode", "value", code);
1747 
1748  release_memory();
1750 }
1751 
1752 static void test_OpenProcess(void)
1753 {
1754  HANDLE hproc;
1755  void *addr1;
1758  BOOL ret;
1759 
1760  /* not exported in all windows versions */
1761  if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1762  win_skip("VirtualAllocEx not found\n");
1763  return;
1764  }
1765 
1766  /* without PROCESS_VM_OPERATION */
1768  ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1769 
1770  SetLastError(0xdeadbeef);
1771  addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1772  ok(!addr1, "VirtualAllocEx should fail\n");
1774  { /* Win9x */
1775  CloseHandle(hproc);
1776  win_skip("VirtualAllocEx not implemented\n");
1777  return;
1778  }
1779  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1780 
1781  read_bytes = 0xdeadbeef;
1782  SetLastError(0xdeadbeef);
1784  ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1785  ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1786 
1787  CloseHandle(hproc);
1788 
1790  ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1791 
1792  addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1793  ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1794 
1795  /* without PROCESS_QUERY_INFORMATION */
1796  SetLastError(0xdeadbeef);
1797  ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1798  "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1799  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1800 
1801  /* without PROCESS_VM_READ */
1802  read_bytes = 0xdeadbeef;
1803  SetLastError(0xdeadbeef);
1804  ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1805  "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1806  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1807  ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1808 
1809  CloseHandle(hproc);
1810 
1812 
1813  memset(&info, 0xcc, sizeof(info));
1814  read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1815  ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1816 
1817  ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1818  ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1819  ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1820  ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1821  ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1822  /* NT reports Protect == 0 for a not committed memory block */
1823  ok(info.Protect == 0 /* NT */ ||
1824  info.Protect == PAGE_NOACCESS, /* Win9x */
1825  "%x != PAGE_NOACCESS\n", info.Protect);
1826  ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1827 
1828  SetLastError(0xdeadbeef);
1829  ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1830  "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1831  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1832 
1833  CloseHandle(hproc);
1834 
1836  if (hproc)
1837  {
1838  SetLastError(0xdeadbeef);
1839  memset(&info, 0xcc, sizeof(info));
1840  read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1841  if (read_bytes) /* win8 */
1842  {
1843  ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1844  ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1845  ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1846  ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1847  ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1848  ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1849  ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
1850  ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1851  }
1852  else /* before win8 */
1853  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1854 
1855  SetLastError(0xdeadbeef);
1856  ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1857  "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1858  ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1859 
1860  CloseHandle(hproc);
1861  }
1862 
1863  ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1864 }
1865 
1866 static void test_GetProcessVersion(void)
1867 {
1868  static char cmdline[] = "winver.exe";
1870  STARTUPINFOA si;
1871  DWORD ret;
1872 
1873  SetLastError(0xdeadbeef);
1874  ret = GetProcessVersion(0);
1875  ok(ret, "GetProcessVersion error %u\n", GetLastError());
1876 
1877  SetLastError(0xdeadbeef);
1879  ok(ret, "GetProcessVersion error %u\n", GetLastError());
1880 
1881  memset(&si, 0, sizeof(si));
1882  si.cb = sizeof(si);
1884  si.wShowWindow = SW_HIDE;
1885  SetLastError(0xdeadbeef);
1886  ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1887  ok(ret, "CreateProcess error %u\n", GetLastError());
1888 
1889  SetLastError(0xdeadbeef);
1890  ret = GetProcessVersion(pi.dwProcessId);
1891  ok(ret, "GetProcessVersion error %u\n", GetLastError());
1892 
1893  SetLastError(0xdeadbeef);
1894  ret = TerminateProcess(pi.hProcess, 0);
1895  ok(ret, "TerminateProcess error %u\n", GetLastError());
1896 
1897  CloseHandle(pi.hProcess);
1898  CloseHandle(pi.hThread);
1899 }
1900 
1902 {
1903  DWORD rc;
1905  static const char harddisk[] = "\\Device\\HarddiskVolume";
1906 
1907  if (!pK32GetProcessImageFileNameA)
1908  {
1909  win_skip("K32GetProcessImageFileNameA is unavailable\n");
1910  return;
1911  }
1912 
1913  /* callers must guess the buffer size */
1914  SetLastError(0xdeadbeef);
1915  rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1917  "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError());
1918 
1919  *process = '\0';
1920  rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1922  if (strncmp(process, harddisk, lstrlenA(harddisk)))
1923  {
1924  todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1925  return;
1926  }
1927 
1928  if (!pQueryFullProcessImageNameA)
1929  win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1930  else
1931  {
1932  CHAR image[MAX_PATH];
1933  DWORD length;
1934 
1935  length = sizeof(image);
1936  expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1938  ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1939  }
1940 }
1941 
1943 {
1944 #define INIT_STR "Just some words"
1945  DWORD length, size;
1947 
1948  if (!pQueryFullProcessImageNameA)
1949  {
1950  win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1951  return;
1952  }
1953 
1954  *module = '\0';
1955  SetLastError(0); /* old Windows don't reset it on success */
1956  size = GetModuleFileNameA(NULL, module, sizeof(module));
1957  ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError());
1958 
1959  /* get the buffer length without \0 terminator */
1960  length = sizeof(buf);
1961  expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1963  ok((buf[0] == '\\' && buf[1] == '\\') ||
1964  lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1965 
1966  /* when the buffer is too small
1967  * - function fail with error ERROR_INSUFFICIENT_BUFFER
1968  * - the size variable is not modified
1969  * tested with the biggest too small size
1970  */
1971  size = length;
1972  sprintf(buf,INIT_STR);
1973  expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1977 
1978  /* retest with smaller buffer size
1979  */
1980  size = 4;
1981  sprintf(buf,INIT_STR);
1982  expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1984  expect_eq_d(4, size);
1986 
1987  /* this is a difference between the ascii and the unicode version
1988  * the unicode version crashes when the size is big enough to hold
1989  * the result while the ascii version throws an error
1990  */
1991  size = 1024;
1992  expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1993  expect_eq_d(1024, size);
1995 }
1996 
1998 {
1999  HANDLE hSelf;
2000  WCHAR module_name[1024], device[1024];
2001  WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
2002  WCHAR buf[1024];
2003  DWORD size, len;
2004 
2005  if (!pQueryFullProcessImageNameW)
2006  {
2007  win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
2008  return;
2009  }
2010 
2011  ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
2012 
2013  /* GetCurrentProcess pseudo-handle */
2014  size = sizeof(buf) / sizeof(buf[0]);
2015  expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
2018 
2020  /* Real handle */
2021  size = sizeof(buf) / sizeof(buf[0]);
2022  expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2025 
2026  /* Buffer too small */
2027  size = lstrlenW(module_name)/2;
2028  lstrcpyW(buf, deviceW);
2029  SetLastError(0xdeadbeef);
2030  expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2031  expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2033  expect_eq_ws_i(deviceW, buf); /* buffer not changed */
2034 
2035  /* Too small - not space for NUL terminator */
2037  SetLastError(0xdeadbeef);
2038  expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2039  expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
2041 
2042  /* NULL buffer */
2043  size = 0;
2044  expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
2045  expect_eq_d(0, size);
2047 
2048  /* Buffer too small */
2049  size = lstrlenW(module_name)/2;
2050  SetLastError(0xdeadbeef);
2052  expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2053  expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2055  expect_eq_ws_i(module_name, buf); /* buffer not changed */
2056 
2057 
2058  /* native path */
2059  size = sizeof(buf) / sizeof(buf[0]);
2060  expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2062  ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2063  ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2064 
2065  module_name[2] = '\0';
2066  *device = '\0';
2067  size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0]));
2068  ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2069  len = lstrlenW(device);
2070  ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2071 
2072  if (size >= lstrlenW(buf))
2073  {
2074  ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2075  }
2076  else
2077  {
2078  ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2079  buf[len] = '\0';
2080  ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2081  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));
2082  }
2083 
2084  CloseHandle(hSelf);
2085 }
2086 
2087 static void test_Handles(void)
2088 {
2090  HANDLE h2, h3;
2091  BOOL ret;
2092  DWORD code;
2093 
2094  ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2095  handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2096  "invalid current process handle %p\n", handle );
2098  ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2099 #ifdef _WIN64
2100  /* truncated handle */
2101  SetLastError( 0xdeadbeef );
2102  handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2104  ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2105  ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2106  /* sign-extended handle */
2107  SetLastError( 0xdeadbeef );
2110  ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2111  /* invalid high-word */
2112  SetLastError( 0xdeadbeef );
2113  handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2115  ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2116  ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2117 #endif
2118 
2120  ok( handle != 0, "handle %p\n", handle );
2126  ok( h2 == 0 ||
2127  broken( h2 == h3) || /* nt4, w2k */
2128  broken( h2 == INVALID_HANDLE_VALUE), /* win9x */
2129  "wrong handle %p/%p\n", h2, h3 );
2131 }
2132 
2133 static void test_IsWow64Process(void)
2134 {
2136  STARTUPINFOA si;
2137  DWORD ret;
2138  BOOL is_wow64;
2139  static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2140  static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2141 
2142  if (!pIsWow64Process)
2143  {
2144  skip("IsWow64Process is not available\n");
2145  return;
2146  }
2147 
2148  memset(&si, 0, sizeof(si));
2149  si.cb = sizeof(si);
2151  si.wShowWindow = SW_HIDE;
2152  ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2153  if (ret)
2154  {
2155  trace("Created process %s\n", cmdline_wow64);
2156  is_wow64 = FALSE;
2157  ret = pIsWow64Process(pi.hProcess, &is_wow64);
2158  ok(ret, "IsWow64Process failed.\n");
2159  ok(is_wow64, "is_wow64 returned FALSE.\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  memset(&si, 0, sizeof(si));
2169  si.cb = sizeof(si);
2171  si.wShowWindow = SW_HIDE;
2172  ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2173  if (ret)
2174  {
2175  trace("Created process %s\n", cmdline);
2176  is_wow64 = TRUE;
2177  ret = pIsWow64Process(pi.hProcess, &is_wow64);
2178  ok(ret, "IsWow64Process failed.\n");
2179  ok(!is_wow64, "is_wow64 returned TRUE.\n");
2180 
2181  ret = TerminateProcess(pi.hProcess, 0);
2182  ok(ret, "TerminateProcess error\n");
2183 
2184  CloseHandle(pi.hProcess);
2185  CloseHandle(pi.hThread);
2186  }
2187 }
2188 
2189 static void test_SystemInfo(void)
2190 {
2191  SYSTEM_INFO si, nsi;
2192  BOOL is_wow64;
2193 
2194  if (!pGetNativeSystemInfo)
2195  {
2196  win_skip("GetNativeSystemInfo is not available\n");
2197  return;
2198  }
2199 
2200  if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2201 
2202  GetSystemInfo(&si);
2203  pGetNativeSystemInfo(&nsi);
2204  if (is_wow64)
2205  {
2206  if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2207  {
2208  ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2209  "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2210  S(U(nsi)).wProcessorArchitecture);
2212  "Expected PROCESSOR_AMD_X8664, got %d\n",
2213  nsi.dwProcessorType);
2214  }
2215  }
2216  else
2217  {
2218  ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2219  "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2220  S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2222  "Expected no difference for dwProcessorType, got %d and %d\n",
2224  }
2225 }
2226 
2227 static void test_RegistryQuota(void)
2228 {
2229  BOOL ret;
2230  DWORD max_quota, used_quota;
2231 
2232  if (!pGetSystemRegistryQuota)
2233  {
2234  win_skip("GetSystemRegistryQuota is not available\n");
2235  return;
2236  }
2237 
2238  ret = pGetSystemRegistryQuota(NULL, NULL);
2239  ok(ret == TRUE,
2240  "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2241 
2242  ret = pGetSystemRegistryQuota(&max_quota, NULL);
2243  ok(ret == TRUE,
2244  "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2245 
2246  ret = pGetSystemRegistryQuota(NULL, &used_quota);
2247  ok(ret == TRUE,
2248  "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2249 
2250  ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2251  ok(ret == TRUE,
2252  "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2253 }
2254 
2255 static void test_TerminateProcess(void)
2256 {
2257  static char cmdline[] = "winver.exe";
2259  STARTUPINFOA si;
2260  DWORD ret;
2261  HANDLE dummy, thread;
2262 
2263  memset(&si, 0, sizeof(si));
2264  si.cb = sizeof(si);
2265  SetLastError(0xdeadbeef);
2267  ok(ret, "CreateProcess error %u\n", GetLastError());
2268 
2269  SetLastError(0xdeadbeef);
2270  thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2271  ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2272 
2273  /* create a not closed thread handle duplicate in the target process */
2274  SetLastError(0xdeadbeef);
2277  ok(ret, "DuplicateHandle error %u\n", GetLastError());
2278 
2279  SetLastError(0xdeadbeef);
2280  ret = TerminateThread(thread, 0);
2281  ok(ret, "TerminateThread error %u\n", GetLastError());
2283 
2284  SetLastError(0xdeadbeef);
2285  ret = TerminateProcess(pi.hProcess, 0);
2286  ok(ret, "TerminateProcess error %u\n", GetLastError());
2287 
2288  CloseHandle(pi.hProcess);
2289  CloseHandle(pi.hThread);
2290 }
2291 
2292 static void test_DuplicateHandle(void)
2293 {
2294  char path[MAX_PATH], file_name[MAX_PATH];
2295  HANDLE f, fmin, out;
2296  DWORD info;
2297  BOOL r;
2298 
2300  GetCurrentProcess(), &out, 0, FALSE,
2302  ok(r, "DuplicateHandle error %u\n", GetLastError());
2304  ok(r, "GetHandleInformation error %u\n", GetLastError());
2305  ok(info == 0, "info = %x\n", info);
2306  ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2307  CloseHandle(out);
2308 
2310  GetCurrentProcess(), &out, 0, TRUE,
2312  ok(r, "DuplicateHandle error %u\n", GetLastError());
2314  ok(r, "GetHandleInformation error %u\n", GetLastError());
2315  ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2316  ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2317  CloseHandle(out);
2318 
2320  GetTempFileNameA(path, "wt", 0, file_name);
2322  if (f == INVALID_HANDLE_VALUE)
2323  {
2324  ok(0, "could not create %s\n", file_name);
2325  return;
2326  }
2327 
2330  ok(r, "DuplicateHandle error %u\n", GetLastError());
2331  ok(f == out, "f != out\n");
2333  ok(r, "GetHandleInformation error %u\n", GetLastError());
2334  ok(info == 0, "info = %x\n", info);
2335 
2338  ok(r, "DuplicateHandle error %u\n", GetLastError());
2339  ok(f == out, "f != out\n");
2341  ok(r, "GetHandleInformation error %u\n", GetLastError());
2342  ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2343 
2345  ok(r, "SetHandleInformation error %u\n", GetLastError());
2348  ok(r, "DuplicateHandle error %u\n", GetLastError());
2349  ok(f != out, "f == out\n");
2351  ok(r, "GetHandleInformation error %u\n", GetLastError());
2352  ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2354  ok(r, "SetHandleInformation error %u\n", GetLastError());
2355 
2356  /* Test if DuplicateHandle allocates first free handle */
2357  if (f > out)
2358  {
2359  fmin = out;
2360  }
2361  else
2362  {
2363  fmin = f;
2364  f = out;
2365  }
2366  CloseHandle(fmin);
2369  ok(r, "DuplicateHandle error %u\n", GetLastError());
2370  ok(f == out, "f != out\n");
2371  CloseHandle(out);
2373 
2374  f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2375  if (!is_console(f))
2376  {
2377  skip("DuplicateHandle on console handle\n");
2378  CloseHandle(f);
2379  return;
2380  }
2381 
2384  ok(r, "DuplicateHandle error %u\n", GetLastError());
2385  todo_wine ok(f != out, "f == out\n");
2386  CloseHandle(out);
2387 }
2388 
2389 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2390 static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2391 {
2393  ULONG_PTR value;
2394  DWORD key;
2395  BOOL ret;
2396 
2398 
2399  ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
2400  if (ret)
2401  {
2402  ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key);
2403  ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2404  ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2405  }
2406 }
2407 
2408 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2409 static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2410 {
2411  BOOL ret;
2412  char buffer[MAX_PATH];
2413  STARTUPINFOA si = {0};
2414 
2415  sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command);
2416 
2417  ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2418  ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError());
2419 }
2420 
2421 #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
2422 static void _test_assigned_proc(int line, HANDLE job, int expected_count, ...)
2423 {
2424  char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20];
2426  DWORD ret_len, pid;
2427  va_list valist;
2428  int n;
2429  BOOL ret;
2430 
2431  memset(buf, 0, sizeof(buf));
2432  ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2433  ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2434  if (ret)
2435  {
2437  ok_(__FILE__, line)(expected_count == pid_list->NumberOfAssignedProcesses,
2438  "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n",
2441  ok_(__FILE__, line)(expected_count == pid_list->NumberOfProcessIdsInList,
2442  "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n",
2444 
2446  for (n = 0; n < min(expected_count, pid_list->NumberOfProcessIdsInList); ++n)
2447  {
2448  pid = va_arg(valist, DWORD);
2449  ok_(__FILE__, line)(pid == pid_list->ProcessIdList[n],
2450  "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n",
2451  n, pid, pid_list->ProcessIdList[n]);
2452  }
2453  va_end(valist);
2454  }
2455 }
2456 
2457 #define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc)
2458 static void _test_accounting(int line, HANDLE job, int total_proc, int active_proc, int terminated_proc)
2459 {
2460  JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting;
2461  DWORD ret_len;
2462  BOOL ret;
2463 
2464  memset(&basic_accounting, 0, sizeof(basic_accounting));
2465  ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting, sizeof(basic_accounting), &ret_len);
2466  ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2467  if (ret)
2468  {
2469  /* Not going to check process times or page faults */
2470 
2471  todo_wine_if(total_proc)
2472  ok_(__FILE__, line)(total_proc == basic_accounting.TotalProcesses,
2473  "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n",
2474  total_proc, basic_accounting.TotalProcesses);
2475  todo_wine_if(active_proc)
2476  ok_(__FILE__, line)(active_proc == basic_accounting.ActiveProcesses,
2477  "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n",
2478  active_proc, basic_accounting.ActiveProcesses);
2479  ok_(__FILE__, line)(terminated_proc == basic_accounting.TotalTerminatedProcesses,
2480  "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n",
2481  terminated_proc, basic_accounting.TotalTerminatedProcesses);
2482  }
2483 }
2484 
2485 static void test_IsProcessInJob(void)
2486 {
2487  HANDLE job, job2;
2489  BOOL ret, out;
2490  DWORD dwret;
2491 
2492  if (!pIsProcessInJob)
2493  {
2494  win_skip("IsProcessInJob not available.\n");
2495  return;
2496  }
2497 
2498  job = pCreateJobObjectW(NULL, NULL);
2499  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2500 
2501  job2 = pCreateJobObjectW(NULL, NULL);
2502  ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError());
2503 
2504  create_process("wait", &pi);
2505 
2506  out = TRUE;
2507  ret = pIsProcessInJob(pi.hProcess, job, &out);
2508  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2509  ok(!out, "IsProcessInJob returned out=%u\n", out);
2510  test_assigned_proc(job, 0);
2511  test_accounting(job, 0, 0, 0);
2512 
2513  out = TRUE;
2514  ret = pIsProcessInJob(pi.hProcess, job2, &out);
2515  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2516  ok(!out, "IsProcessInJob returned out=%u\n", out);
2517  test_assigned_proc(job2, 0);
2518  test_accounting(job2, 0, 0, 0);
2519 
2520  out = TRUE;
2521  ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2522  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2523  ok(!out, "IsProcessInJob returned out=%u\n", out);
2524 
2525  ret = pAssignProcessToJobObject(job, pi.hProcess);
2526  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2527 
2528  out = FALSE;
2529  ret = pIsProcessInJob(pi.hProcess, job, &out);
2530  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2531  ok(out, "IsProcessInJob returned out=%u\n", out);
2532  test_assigned_proc(job, 1, pi.dwProcessId);
2533  test_accounting(job, 1, 1, 0);
2534 
2535  out = TRUE;
2536  ret = pIsProcessInJob(pi.hProcess, job2, &out);
2537  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2538  ok(!out, "IsProcessInJob returned out=%u\n", out);
2539  test_assigned_proc(job2, 0);
2540  test_accounting(job2, 0, 0, 0);
2541 
2542  out = FALSE;
2543  ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2544  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2545  ok(out, "IsProcessInJob returned out=%u\n", out);
2546 
2547  TerminateProcess(pi.hProcess, 0);
2548 
2549  dwret = WaitForSingleObject(pi.hProcess, 1000);
2550  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2551 
2552  out = FALSE;
2553  ret = pIsProcessInJob(pi.hProcess, job, &out);
2554  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2555  ok(out, "IsProcessInJob returned out=%u\n", out);
2556  test_assigned_proc(job, 0);
2557  test_accounting(job, 1, 0, 0);
2558 
2559  CloseHandle(pi.hProcess);
2560  CloseHandle(pi.hThread);
2561  CloseHandle(job);
2562  CloseHandle(job2);
2563 }
2564 
2565 static void test_TerminateJobObject(void)
2566 {
2567  HANDLE job;
2569  BOOL ret;
2570  DWORD dwret;
2571 
2572  job = pCreateJobObjectW(NULL, NULL);
2573  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2574  test_assigned_proc(job, 0);
2575  test_accounting(job, 0, 0, 0);
2576 
2577  create_process("wait", &pi);
2578 
2579  ret = pAssignProcessToJobObject(job, pi.hProcess);
2580  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2581  test_assigned_proc(job, 1, pi.dwProcessId);
2582  test_accounting(job, 1, 1, 0);
2583 
2584  ret = pTerminateJobObject(job, 123);
2585  ok(ret, "TerminateJobObject error %u\n", GetLastError());
2586 
2587  dwret = WaitForSingleObject(pi.hProcess, 1000);
2588  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2589  if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2590  test_assigned_proc(job, 0);
2591  test_accounting(job, 1, 0, 0);
2592 
2593  ret = GetExitCodeProcess(pi.hProcess, &dwret);
2594  ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
2595  ok(dwret == 123 || broken(dwret == 0) || broken(dwret == 259) /* randomly fails on Win 2000 / XP */,
2596  "wrong exitcode %u\n", dwret);
2597 
2598  CloseHandle(pi.hProcess);
2599  CloseHandle(pi.hThread);
2600 
2601  /* Test adding an already terminated process to a job object */
2602  create_process("exit", &pi);
2603 
2604  dwret = WaitForSingleObject(pi.hProcess, 1000);
2605  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2606 
2607  SetLastError(0xdeadbeef);
2608  ret = pAssignProcessToJobObject(job, pi.hProcess);
2609  ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2611  test_assigned_proc(job, 0);
2612  test_accounting(job, 1, 0, 0);
2613 
2614  CloseHandle(pi.hProcess);
2615  CloseHandle(pi.hThread);
2616 
2617  CloseHandle(job);
2618 }
2619 
2621 {
2622  char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2624  JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2625  JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2626  DWORD dwret, ret_len;
2628  HANDLE job;
2629  BOOL ret;
2630 
2631  job = pCreateJobObjectW(NULL, NULL);
2632  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2633 
2634  /* Only active processes are returned */
2635  create_process("exit", &pi[0]);
2636  ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2637  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2638  dwret = WaitForSingleObject(pi[0].hProcess, 1000);
2639  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2640 
2641  CloseHandle(pi[0].hProcess);
2642  CloseHandle(pi[0].hThread);
2643 
2644  create_process("wait", &pi[0]);
2645  ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2646  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2647 
2648  create_process("wait", &pi[1]);
2649  ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2650  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2651 
2652  SetLastError(0xdeadbeef);
2655  ok(!ret, "QueryInformationJobObject expected failure\n");
2657 
2658  SetLastError(0xdeadbeef);
2659  memset(buf, 0, sizeof(buf));
2660  pid_list->NumberOfAssignedProcesses = 42;
2661  pid_list->NumberOfProcessIdsInList = 42;
2664  todo_wine
2665  ok(!ret, "QueryInformationJobObject expected failure\n");
2666  todo_wine
2668  if (ret)
2669  {
2670  todo_wine
2671  expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2672  todo_wine
2673  expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2674  }
2675 
2676  memset(buf, 0, sizeof(buf));
2677  ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2678  ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2679  if(ret)
2680  {
2681  if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2682  win_skip("Number of assigned processes broken on Win 8\n");
2683  else
2684  {
2685  ULONG_PTR *list = pid_list->ProcessIdList;
2686 
2687  todo_wine
2689  "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2690 
2691  todo_wine
2692  expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2693  todo_wine
2694  expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2695  todo_wine
2696  expect_eq_d(pi[0].dwProcessId, list[0]);
2697  todo_wine
2698  expect_eq_d(pi[1].dwProcessId, list[1]);
2699  }
2700  }
2701 
2702  /* test JobObjectBasicLimitInformation */
2703  ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2704  sizeof(*basic_limit_info) - 1, &ret_len);
2705  ok(!ret, "QueryInformationJobObject expected failure\n");
2707 
2708  ret_len = 0xdeadbeef;
2709  memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2710  ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2711  sizeof(*basic_limit_info), &ret_len);
2712  ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2713  ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2714  expect_eq_d(0, basic_limit_info->LimitFlags);
2715 
2716  /* test JobObjectExtendedLimitInformation */
2717  ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2718  sizeof(ext_limit_info) - 1, &ret_len);
2719  ok(!ret, "QueryInformationJobObject expected failure\n");
2721 
2722  ret_len = 0xdeadbeef;
2723  memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2724  ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2725  sizeof(ext_limit_info), &ret_len);
2726  ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2727  ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2728  expect_eq_d(0, basic_limit_info->LimitFlags);
2729 
2730  TerminateProcess(pi[0].hProcess, 0);
2731  CloseHandle(pi[0].hProcess);
2732  CloseHandle(pi[0].hThread);
2733 
2734  TerminateProcess(pi[1].hProcess, 0);
2735  CloseHandle(pi[1].hProcess);
2736  CloseHandle(pi[1].hThread);
2737 
2738  CloseHandle(job);
2739 }
2740 
2741 static void test_CompletionPort(void)
2742 {
2745  HANDLE job, port;
2746  DWORD dwret;
2747  BOOL ret;
2748 
2749  job = pCreateJobObjectW(NULL, NULL);
2750  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2751 
2752  port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2753  ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
2754 
2755  port_info.CompletionKey = job;
2756  port_info.CompletionPort = port;
2757  ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2758  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2759 
2760  create_process("wait", &pi);
2761 
2762  ret = pAssignProcessToJobObject(job, pi.hProcess);
2763  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2764 
2766 
2767  TerminateProcess(pi.hProcess, 0);
2768  dwret = WaitForSingleObject(pi.hProcess, 1000);
2769  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2770 
2773 
2774  CloseHandle(pi.hProcess);
2775  CloseHandle(pi.hThread);
2776  CloseHandle(job);
2777  CloseHandle(port);
2778 }
2779 
2780 static void test_KillOnJobClose(void)
2781 {
2784  DWORD dwret;
2785  HANDLE job;
2786  BOOL ret;
2787 
2788  job = pCreateJobObjectW(NULL, NULL);
2789  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2790 
2792  ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2794  {
2795  win_skip("Kill on job close limit not available\n");
2796  return;
2797  }
2798  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2799  test_assigned_proc(job, 0);
2800  test_accounting(job, 0, 0, 0);
2801 
2802  create_process("wait", &pi);
2803 
2804  ret = pAssignProcessToJobObject(job, pi.hProcess);
2805  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2806  test_assigned_proc(job, 1, pi.dwProcessId);
2807  test_accounting(job, 1, 1, 0);
2808 
2809  CloseHandle(job);
2810 
2811  dwret = WaitForSingleObject(pi.hProcess, 1000);
2812  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2813  if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2814 
2815  CloseHandle(pi.hProcess);
2816  CloseHandle(pi.hThread);
2817 }
2818 
2819 static void test_WaitForJobObject(void)
2820 {
2821  HANDLE job;
2823  BOOL ret;
2824  DWORD dwret;
2825 
2826  /* test waiting for a job object when the process is killed */
2827  job = pCreateJobObjectW(NULL, NULL);
2828  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2829 
2830  dwret = WaitForSingleObject(job, 100);
2831  ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2832 
2833  create_process("wait", &pi);
2834 
2835  ret = pAssignProcessToJobObject(job, pi.hProcess);
2836  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2837 
2838  dwret = WaitForSingleObject(job, 100);
2839  ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2840 
2841  ret = pTerminateJobObject(job, 123);
2842  ok(ret, "TerminateJobObject error %u\n", GetLastError());
2843 
2844  dwret = WaitForSingleObject(job, 500);
2845  ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2846  "WaitForSingleObject returned %u\n", dwret);
2847 
2848  if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2849  {
2850 #ifdef __REACTOS__
2851  if (!ret)
2852  {
2853  ok(0, "HACK: Killing process to speed up the test\n");
2854  TerminateProcess(pi.hProcess, 0);
2855  }
2856 #endif
2857  CloseHandle(pi.hProcess);
2858  CloseHandle(pi.hThread);
2859  CloseHandle(job);
2860  win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2861  return;
2862  }
2863 
2864  /* the object is not reset immediately */
2865  dwret = WaitForSingleObject(job, 100);
2866  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2867 
2868  CloseHandle(pi.hProcess);
2869  CloseHandle(pi.hThread);
2870 
2871  /* creating a new process doesn't reset the signalled state */
2872  create_process("wait", &pi);
2873 
2874  ret = pAssignProcessToJobObject(job, pi.hProcess);
2875  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2876 
2877  dwret = WaitForSingleObject(job, 100);
2878  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2879 
2880  ret = pTerminateJobObject(job, 123);
2881  ok(ret, "TerminateJobObject error %u\n", GetLastError());
2882 
2883  CloseHandle(pi.hProcess);
2884  CloseHandle(pi.hThread);
2885 
2886  CloseHandle(job);
2887 
2888  /* repeat the test, but this time the process terminates properly */
2889  job = pCreateJobObjectW(NULL, NULL);
2890  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2891 
2892  dwret = WaitForSingleObject(job, 100);
2893  ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2894 
2895  create_process("exit", &pi);
2896 
2897  ret = pAssignProcessToJobObject(job, pi.hProcess);
2898  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2899 
2900  dwret = WaitForSingleObject(job, 100);
2901  ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2902 
2903  CloseHandle(pi.hProcess);
2904  CloseHandle(pi.hThread);
2905  CloseHandle(job);
2906 }
2907 
2909 {
2910  HANDLE job;
2911  BOOL ret;
2912 
2913  job = pCreateJobObjectW(NULL, NULL);
2914  ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2915 
2916  ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2917  ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2919  test_accounting(job, 1, 1, 0);
2920 
2921  return job;
2922 }
2923 
2925 {
2926  char buffer[MAX_PATH];
2928  STARTUPINFOA si = {0};
2929  DWORD dwret;
2930  BOOL ret, out;
2931 
2932  if (!pIsProcessInJob)
2933  {
2934  win_skip("IsProcessInJob not available.\n");
2935  return;
2936  }
2937 
2938  sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2939 
2940  ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2941  ok(ret, "CreateProcessA error %u\n", GetLastError());
2942 
2943  out = FALSE;
2944  ret = pIsProcessInJob(pi.hProcess, job, &out);
2945  ok(ret, "IsProcessInJob error %u\n", GetLastError());
2946  ok(out, "IsProcessInJob returned out=%u\n", out);
2947  test_assigned_proc(job, 2, GetCurrentProcessId(), pi.dwProcessId);
2948  test_accounting(job, 2, 2, 0);
2949 
2950  dwret = WaitForSingleObject(pi.hProcess, 1000);
2951  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2952 
2953  CloseHandle(pi.hProcess);
2954  CloseHandle(pi.hThread);
2955 }
2956 
2958 {
2961  STARTUPINFOA si = {0};
2962  char buffer[MAX_PATH];
2963  BOOL ret, out;
2964  DWORD dwret;
2965 
2966  if (!pIsProcessInJob)
2967  {
2968  win_skip("IsProcessInJob not available.\n");
2969  return;
2970  }
2971 
2972  sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2973 
2975  ok(!ret, "CreateProcessA expected failure\n");
2978  test_accounting(job, 2, 1, 0);
2979 
2980  if (ret)
2981  {
2982  TerminateProcess(pi.hProcess, 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  }
2990 
2992  ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2993  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2994 
2996  ok(ret, "CreateProcessA error %u\n", GetLastError());
2997 
2998  ret = pIsProcessInJob(pi.hProcess, job, &out);
2999  ok(ret, "IsProcessInJob error %u\n", GetLastError());
3000  ok(!out, "IsProcessInJob returned out=%u\n", out);
3002  test_accounting(job, 2, 1, 0);
3003 
3004  dwret = WaitForSingleObject(pi.hProcess, 1000);
3005  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
3006 
3007  CloseHandle(pi.hProcess);
3008  CloseHandle(pi.hThread);
3009 
3011  ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3012  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
3013 
3014  ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3015  ok(ret, "CreateProcess error %u\n", GetLastError());
3016 
3017  ret = pIsProcessInJob(pi.hProcess, job, &out);
3018  ok(ret, "IsProcessInJob error %u\n", GetLastError());
3019  ok(!out, "IsProcessInJob returned out=%u\n", out);
3021  test_accounting(job, 2, 1, 0);
3022 
3023  dwret = WaitForSingleObject(pi.hProcess, 1000);
3024  ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
3025 
3026  CloseHandle(pi.hProcess);
3027  CloseHandle(pi.hThread);
3028 
3029  /* unset breakaway ok */
3030  limit_info.BasicLimitInformation.LimitFlags = 0;
3031  ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3032  ok(ret, "SetInformationJobObject error %u\n", GetLastError());
3033 }
3034 
3035 static void test_StartupNoConsole(void)
3036 {
3037 #ifndef _WIN64
3038  char buffer[MAX_PATH];
3041 
3042  memset(&startup, 0, sizeof(startup));
3043  startup.cb = sizeof(startup);
3044  startup.dwFlags = STARTF_USESHOWWINDOW;
3045  startup.wShowWindow = SW_SHOWNORMAL;
3047  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3049  &info), "CreateProcess\n");
3050  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3052  okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3053  okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3054  okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3055  okChildInt("TEB", "hStdInput", 0);
3056  okChildInt("TEB", "hStdOutput", 0);
3057  okChildInt("TEB", "hStdError", 0);
3058  release_memory();
3060 #endif
3061 }
3062 
3063 static void test_DetachConsoleHandles(void)
3064 {
3065 #ifndef _WIN64
3066  char buffer[MAX_PATH];
3069  UINT result;
3070 
3071  memset(&startup, 0, sizeof(startup));
3072  startup.cb = sizeof(startup);
3074  startup.wShowWindow = SW_SHOWNORMAL;
3075  startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
3076  startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
3077  startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
3079  sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3081  &info), "CreateProcess\n");
3082  ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3084 
3085  result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile);
3086  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3087  result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile);
3088  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3089  result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile);
3090  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3091  result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile);
3092  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3093  result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile);
3094  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3095  result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile);
3096  ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3097 
3098  release_memory();
3100 #endif
3101 }
3102 
3103 #if defined(__i386__) || defined(__x86_64__)
3104 static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi,
3106