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 
66 static HINSTANCE hkernel32, hntdll;
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 {
131     memory_index = memory;
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 
221     myARGC = winetest_get_mainargs( &myARGV );
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);
295     vsprintf(buffer, fmt, valist);
296     va_end(valist);
297     WriteFile(h, buffer, strlen(buffer), &w, NULL);
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];
316     HANDLE              hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
317     HANDLE              snapshot;
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,
333                 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute,
334                 siA.dwFlags, siA.wShowWindow,
335                 (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError);
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,
355                 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute,
356                 siW.dwFlags, siW.wShowWindow,
357                 (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError);
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     }
378     CloseHandle(snapshot);
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",
384                 pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID,
385                 pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase,
386                 pe.dwFlags, encodeA(pe.szExeFile));
387 
388     /* output of environment (Ansi) */
389     ptrA_save = ptrA = GetEnvironmentStringsA();
390     if (ptrA)
391     {
392         char    env_var[MAX_LISTED_ENV_VAR];
393 
394         childPrintf(hFile, "[EnvironmentA]\n");
395         i = 0;
396         while (*ptrA)
397         {
398             lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR);
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     {
411         WCHAR   env_var[MAX_LISTED_ENV_VAR];
412 
413         childPrintf(hFile, "[EnvironmentW]\n");
414         i = 0;
415         while (*ptrW)
416         {
417             lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1);
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     {
436         CONSOLE_SCREEN_BUFFER_INFO	sbi;
437         HANDLE hConIn  = GetStdHandle(STD_INPUT_HANDLE);
438         HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
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",
449                         sbi.dwMaximumWindowSize.X, sbi.dwMaximumWindowSize.Y);
450         }
451         childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
452                     GetConsoleCP(), GetConsoleOutputCP());
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);
461         if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
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;
477         ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition);
478         ok( ret, "Setting cursor position (%d)\n", GetLastError());
479     }
480     if (option && strcmp(option, "stdhandle") == 0)
481     {
482         HANDLE hStdIn  = GetStdHandle(STD_INPUT_HANDLE);
483         HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
484 
485         if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE)
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);
499         CloseHandle(hFile);
500         ExitProcess(123);
501     }
502 
503     CloseHandle(hFile);
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 {
593     UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile );
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];
605     PROCESS_INFORMATION	info;
606     STARTUPINFOA	startup,si;
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 
618     get_file_name(resfile);
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 */
624     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
641     DeleteFileA(resfile);
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 
658     get_file_name(resfile);
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 */
664     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
681     DeleteFileA(resfile);
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 
698     get_file_name(resfile);
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 */
704     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
721     DeleteFileA(resfile);
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 
738     get_file_name(resfile);
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 */
744     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
761     DeleteFileA(resfile);
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 
778     get_file_name(resfile);
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 */
784     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
803     DeleteFileA(resfile);
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 
820     get_file_name(resfile);
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 */
826     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
843     DeleteFileA(resfile);
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 
860     get_file_name(resfile);
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 */
866     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
883     DeleteFileA(resfile);
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];
892     PROCESS_INFORMATION	info;
893     STARTUPINFOA	startup;
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 */
902     get_file_name(resfile);
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 */
908     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
917     DeleteFileA(resfile);
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 */
925     get_file_name(resfile);
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 */
931     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
942     DeleteFileA(resfile);
943 
944     /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
945     get_file_name(resfile);
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);
949     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
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 */
954     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
955     CloseHandle(info.hThread);
956     CloseHandle(info.hProcess);
957     sprintf(buffer, "./%s", exename);
958     okChildString("Arguments", "argvA0", buffer);
959     release_memory();
960     DeleteFileA(resfile);
961 
962     get_file_name(resfile);
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);
966     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
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 */
971     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
972     CloseHandle(info.hThread);
973     CloseHandle(info.hProcess);
974     sprintf(buffer, ".\\%s", exename);
975     okChildString("Arguments", "argvA0", buffer);
976     release_memory();
977     DeleteFileA(resfile);
978 
979     get_file_name(resfile);
980     GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
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);
988     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
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 */
993     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
1000     DeleteFileA(resfile);
1001 
1002     /* Using AppName */
1003     get_file_name(resfile);
1004     GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
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 */
1018     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
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();
1026     DeleteFileA(resfile);
1027 
1028     if (0) /* Test crashes on NT-based Windows. */
1029     {
1030         /* Test NULL application name and command line parameters. */
1031         SetLastError(0xdeadbeef);
1032         ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1033         ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1034         ok(GetLastError() == ERROR_INVALID_PARAMETER,
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);
1042     ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1043     ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1044     ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
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");
1055     ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
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");
1064     ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
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);
1075     ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
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);
1086     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
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];
1099     PROCESS_INFORMATION	info;
1100     STARTUPINFOA	startup;
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 */
1110     get_file_name(resfile);
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 */
1117     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1118     CloseHandle(info.hThread);
1119     CloseHandle(info.hProcess);
1120 
1121     okChildIString("Misc", "CurrDirA", windir);
1122     release_memory();
1123     DeleteFileA(resfile);
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));
1134     ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L,
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];
1143     STARTUPINFOA        startup;
1144     PROCESS_INFORMATION info;
1145     HANDLE              process, thread, snapshot;
1146     PROCESSENTRY32      pe;
1147     THREADENTRY32       te;
1148     DWORD               ret;
1149     int                 i;
1150 
1151     memset(&startup, 0, sizeof(startup));
1152     startup.cb = sizeof(startup);
1153     startup.dwFlags = STARTF_USESHOWWINDOW;
1154     startup.wShowWindow = SW_SHOWNORMAL;
1155 
1156     get_file_name(resfile);
1157     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1158     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1159     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1160     CloseHandle(info.hProcess);
1161     CloseHandle(info.hThread);
1162 
1163     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1164     okChildInt("Toolhelp", "cntUsage", 0);
1165     okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1166     okChildInt("Toolhelp", "th32ModuleID", 0);
1167     okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1168     /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1169     okChildInt("Toolhelp", "dwFlags", 0);
1170 
1171     release_memory();
1172     DeleteFileA(resfile);
1173 
1174     get_file_name(resfile);
1175     sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile);
1176     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1177     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1178 
1179     process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1180     ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1181     CloseHandle(process);
1182 
1183     CloseHandle(info.hProcess);
1184     CloseHandle(info.hThread);
1185 
1186     for (i = 0; i < 20; i++)
1187     {
1188         SetLastError(0xdeadbeef);
1189         process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1190         ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError());
1191         if (!process) break;
1192         CloseHandle(process);
1193         Sleep(100);
1194     }
1195     /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1196     ok(i < 20 || broken(i == 20), "process object not released\n");
1197 
1198     snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1199     ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1200     memset(&pe, 0, sizeof(pe));
1201     pe.dwSize = sizeof(pe);
1202     if (pProcess32First(snapshot, &pe))
1203     {
1204         while (pe.th32ParentProcessID != info.dwProcessId)
1205             if (!pProcess32Next(snapshot, &pe)) break;
1206     }
1207     CloseHandle(snapshot);
1208     ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n");
1209 
1210     process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID);
1211     ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1212 
1213     snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1214     ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1215     memset(&te, 0, sizeof(te));
1216     te.dwSize = sizeof(te);
1217     if (pThread32First(snapshot, &te))
1218     {
1219         while (te.th32OwnerProcessID != pe.th32ProcessID)
1220             if (!pThread32Next(snapshot, &te)) break;
1221     }
1222     CloseHandle(snapshot);
1223     ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1224 
1225     thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID);
1226     ok(thread != NULL, "OpenThread failed %u\n", GetLastError());
1227     ret = ResumeThread(thread);
1228     ok(ret == 1, "expected 1, got %u\n", ret);
1229     CloseHandle(thread);
1230 
1231     ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1232     CloseHandle(process);
1233 
1234     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1235     okChildInt("Toolhelp", "cntUsage", 0);
1236     okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1237     okChildInt("Toolhelp", "th32ModuleID", 0);
1238     okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1239     /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1240     okChildInt("Toolhelp", "dwFlags", 0);
1241 
1242     release_memory();
1243     DeleteFileA(resfile);
1244 }
1245 
1246 static BOOL is_str_env_drive_dir(const char* str)
1247 {
1248     return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1249         str[3] == '=' && str[4] == str[1];
1250 }
1251 
1252 /* compared expected child's environment (in gesA) from actual
1253  * environment our child got
1254  */
1255 static void cmpEnvironment(const char* gesA)
1256 {
1257     int                 i, clen;
1258     const char*         ptrA;
1259     char*               res;
1260     char                key[32];
1261     BOOL                found;
1262 
1263     clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1264 
1265     /* now look each parent env in child */
1266     if ((ptrA = gesA) != NULL)
1267     {
1268         while (*ptrA)
1269         {
1270             for (i = 0; i < clen; i++)
1271             {
1272                 sprintf(key, "env%d", i);
1273                 res = getChildString("EnvironmentA", key);
1274                 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1275                     break;
1276             }
1277             found = i < clen;
1278             ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1279 
1280             ptrA += strlen(ptrA) + 1;
1281             release_memory();
1282         }
1283     }
1284     /* and each child env in parent */
1285     for (i = 0; i < clen; i++)
1286     {
1287         sprintf(key, "env%d", i);
1288         res = getChildString("EnvironmentA", key);
1289         if ((ptrA = gesA) != NULL)
1290         {
1291             while (*ptrA)
1292             {
1293                 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1294                     break;
1295                 ptrA += strlen(ptrA) + 1;
1296             }
1297             if (!*ptrA) ptrA = NULL;
1298         }
1299 
1300         if (!is_str_env_drive_dir(res))
1301         {
1302             found = ptrA != NULL;
1303             ok(found, "Child-env string %s isn't in parent process\n", res);
1304         }
1305         /* else => should also test we get the right per drive default directory here... */
1306     }
1307 }
1308 
1309 static void test_Environment(void)
1310 {
1311     char                buffer[MAX_PATH];
1312     PROCESS_INFORMATION	info;
1313     STARTUPINFOA	startup;
1314     char                *child_env;
1315     int                 child_env_len;
1316     char                *ptr;
1317     char                *ptr2;
1318     char                *env;
1319     int                 slen;
1320 
1321     memset(&startup, 0, sizeof(startup));
1322     startup.cb = sizeof(startup);
1323     startup.dwFlags = STARTF_USESHOWWINDOW;
1324     startup.wShowWindow = SW_SHOWNORMAL;
1325 
1326     /* the basics */
1327     get_file_name(resfile);
1328     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1329     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1330     /* wait for child to terminate */
1331     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1332     /* child process has changed result file, so let profile functions know about it */
1333     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1334 
1335     env = GetEnvironmentStringsA();
1336     cmpEnvironment(env);
1337     release_memory();
1338     DeleteFileA(resfile);
1339 
1340     memset(&startup, 0, sizeof(startup));
1341     startup.cb = sizeof(startup);
1342     startup.dwFlags = STARTF_USESHOWWINDOW;
1343     startup.wShowWindow = SW_SHOWNORMAL;
1344 
1345     /* the basics */
1346     get_file_name(resfile);
1347     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1348 
1349     child_env_len = 0;
1350     ptr = env;
1351     while(*ptr)
1352     {
1353         slen = strlen(ptr)+1;
1354         child_env_len += slen;
1355         ptr += slen;
1356     }
1357     /* Add space for additional environment variables */
1358     child_env_len += 256;
1359     child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1360 
1361     ptr = child_env;
1362     sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1363     ptr += strlen(ptr) + 1;
1364     strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1365     ptr += strlen(ptr) + 1;
1366     strcpy(ptr, "FOO=BAR");
1367     ptr += strlen(ptr) + 1;
1368     strcpy(ptr, "BAR=FOOBAR");
1369     ptr += strlen(ptr) + 1;
1370     /* copy all existing variables except:
1371      * - WINELOADER
1372      * - PATH (already set above)
1373      * - the directory definitions (=[A-Z]:=)
1374      */
1375     for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1376     {
1377         if (strncmp(ptr2, "PATH=", 5) != 0 &&
1378             strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1379             !is_str_env_drive_dir(ptr2))
1380         {
1381             strcpy(ptr, ptr2);
1382             ptr += strlen(ptr) + 1;
1383         }
1384     }
1385     *ptr = '\0';
1386     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1387     /* wait for child to terminate */
1388     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1389     /* child process has changed result file, so let profile functions know about it */
1390     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1391 
1392     cmpEnvironment(child_env);
1393 
1394     HeapFree(GetProcessHeap(), 0, child_env);
1395     FreeEnvironmentStringsA(env);
1396     release_memory();
1397     DeleteFileA(resfile);
1398 }
1399 
1400 static  void    test_SuspendFlag(void)
1401 {
1402     char                buffer[MAX_PATH];
1403     PROCESS_INFORMATION	info;
1404     STARTUPINFOA       startup, us;
1405     DWORD               exit_status;
1406     char *result;
1407 
1408     /* let's start simplistic */
1409     memset(&startup, 0, sizeof(startup));
1410     startup.cb = sizeof(startup);
1411     startup.dwFlags = STARTF_USESHOWWINDOW;
1412     startup.wShowWindow = SW_SHOWNORMAL;
1413 
1414     get_file_name(resfile);
1415     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1416     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1417 
1418     ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1419     Sleep(1000);
1420     ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1421     ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1422 
1423     /* wait for child to terminate */
1424     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1425     /* child process has changed result file, so let profile functions know about it */
1426     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1427 
1428     GetStartupInfoA(&us);
1429 
1430     okChildInt("StartupInfoA", "cb", startup.cb);
1431     okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1432     result = getChildString( "StartupInfoA", "lpTitle" );
1433     ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1434         "expected '%s' or null, got '%s'\n", selfname, result );
1435     okChildInt("StartupInfoA", "dwX", startup.dwX);
1436     okChildInt("StartupInfoA", "dwY", startup.dwY);
1437     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1438     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1439     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1440     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1441     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1442     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1443     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1444     release_memory();
1445     DeleteFileA(resfile);
1446 }
1447 
1448 static  void    test_DebuggingFlag(void)
1449 {
1450     char                buffer[MAX_PATH];
1451     void               *processbase = NULL;
1452     PROCESS_INFORMATION	info;
1453     STARTUPINFOA       startup, us;
1454     DEBUG_EVENT         de;
1455     unsigned            dbg = 0;
1456     char *result;
1457 
1458     /* let's start simplistic */
1459     memset(&startup, 0, sizeof(startup));
1460     startup.cb = sizeof(startup);
1461     startup.dwFlags = STARTF_USESHOWWINDOW;
1462     startup.wShowWindow = SW_SHOWNORMAL;
1463 
1464     get_file_name(resfile);
1465     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1466     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1467 
1468     /* get all startup events up to the entry point break exception */
1469     do
1470     {
1471         ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1472         ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1473         if (!dbg)
1474         {
1475             ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1476                "first event: %d\n", de.dwDebugEventCode);
1477             processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1478         }
1479         if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1480         ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT ||
1481            de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1482     } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1483 
1484     ok(dbg, "I have seen a debug event\n");
1485     /* wait for child to terminate */
1486     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1487     /* child process has changed result file, so let profile functions know about it */
1488     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1489 
1490     GetStartupInfoA(&us);
1491 
1492     okChildInt("StartupInfoA", "cb", startup.cb);
1493     okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1494     result = getChildString( "StartupInfoA", "lpTitle" );
1495     ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1496         "expected '%s' or null, got '%s'\n", selfname, result );
1497     okChildInt("StartupInfoA", "dwX", startup.dwX);
1498     okChildInt("StartupInfoA", "dwY", startup.dwY);
1499     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1500     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1501     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1502     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1503     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1504     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1505     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1506     release_memory();
1507     DeleteFileA(resfile);
1508 }
1509 
1510 static BOOL is_console(HANDLE h)
1511 {
1512     return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1513 }
1514 
1515 static void test_Console(void)
1516 {
1517     char                buffer[MAX_PATH];
1518     PROCESS_INFORMATION	info;
1519     STARTUPINFOA       startup, us;
1520     SECURITY_ATTRIBUTES sa;
1521     CONSOLE_SCREEN_BUFFER_INFO	sbi, sbiC;
1522     DWORD               modeIn, modeOut, modeInC, modeOutC;
1523     DWORD               cpIn, cpOut, cpInC, cpOutC;
1524     DWORD               w;
1525     HANDLE              hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1526     const char*         msg = "This is a std-handle inheritance test.";
1527     unsigned            msg_len;
1528     BOOL                run_tests = TRUE;
1529     char *result;
1530 
1531     memset(&startup, 0, sizeof(startup));
1532     startup.cb = sizeof(startup);
1533     startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1534     startup.wShowWindow = SW_SHOWNORMAL;
1535 
1536     sa.nLength = sizeof(sa);
1537     sa.lpSecurityDescriptor = NULL;
1538     sa.bInheritHandle = TRUE;
1539 
1540     startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1541     startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1542 
1543     /* first, we need to be sure we're attached to a console */
1544     if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1545     {
1546         /* we're not attached to a console, let's do it */
1547         AllocConsole();
1548         startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1549         startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1550     }
1551     /* now verify everything's ok */
1552     ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1553     ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1554     startup.hStdError = startup.hStdOutput;
1555 
1556     ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1557     ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1558     ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1559     cpIn = GetConsoleCP();
1560     cpOut = GetConsoleOutputCP();
1561 
1562     get_file_name(resfile);
1563     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile);
1564     ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1565 
1566     /* wait for child to terminate */
1567     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1568     /* child process has changed result file, so let profile functions know about it */
1569     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1570 
1571     /* now get the modification the child has made, and resets parents expected values */
1572     ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1573     ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1574     ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1575 
1576     SetConsoleMode(startup.hStdInput, modeIn);
1577     SetConsoleMode(startup.hStdOutput, modeOut);
1578 
1579     cpInC = GetConsoleCP();
1580     cpOutC = GetConsoleOutputCP();
1581 
1582     /* Try to set invalid CP */
1583     SetLastError(0xdeadbeef);
1584     ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1585     ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1586        broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1587        "GetLastError: expecting %u got %u\n",
1588        ERROR_INVALID_PARAMETER, GetLastError());
1589     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1590         run_tests = FALSE;
1591 
1592 
1593     SetLastError(0xdeadbeef);
1594     ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1595     ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1596        broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1597        "GetLastError: expecting %u got %u\n",
1598        ERROR_INVALID_PARAMETER, GetLastError());
1599 
1600     SetConsoleCP(cpIn);
1601     SetConsoleOutputCP(cpOut);
1602 
1603     GetStartupInfoA(&us);
1604 
1605     okChildInt("StartupInfoA", "cb", startup.cb);
1606     okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1607     result = getChildString( "StartupInfoA", "lpTitle" );
1608     ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1609         "expected '%s' or null, got '%s'\n", selfname, result );
1610     okChildInt("StartupInfoA", "dwX", startup.dwX);
1611     okChildInt("StartupInfoA", "dwY", startup.dwY);
1612     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1613     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1614     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1615     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1616     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1617     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1618     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1619 
1620     /* check child correctly inherited the console */
1621     okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1622     okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1623     okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1624     okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1625     okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1626     okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1627     okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1628     okChildInt("Console", "Attributes", sbi.wAttributes);
1629     okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1630     okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1631     okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1632     okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1633     okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1634     okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1635     okChildInt("Console", "InputCP", cpIn);
1636     okChildInt("Console", "OutputCP", cpOut);
1637     okChildInt("Console", "InputMode", modeIn);
1638     okChildInt("Console", "OutputMode", modeOut);
1639 
1640     if (run_tests)
1641     {
1642         ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1643         ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1644     }
1645     else
1646         win_skip("Setting the codepage is not implemented\n");
1647 
1648     ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1649     ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1650     trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1651     ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1652 
1653     release_memory();
1654     DeleteFileA(resfile);
1655 
1656     ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1657     ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(),
1658                        &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1659        "Duplicating as inheritable child-output pipe\n");
1660     CloseHandle(hChildOut);
1661 
1662     ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1663     ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(),
1664                        &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1665        "Duplicating as inheritable child-input pipe\n");
1666     CloseHandle(hChildIn);
1667 
1668     memset(&startup, 0, sizeof(startup));
1669     startup.cb = sizeof(startup);
1670     startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1671     startup.wShowWindow = SW_SHOWNORMAL;
1672     startup.hStdInput = hChildInInh;
1673     startup.hStdOutput = hChildOutInh;
1674     startup.hStdError = hChildOutInh;
1675 
1676     get_file_name(resfile);
1677     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile);
1678     ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1679     ok(CloseHandle(hChildInInh), "Closing handle\n");
1680     ok(CloseHandle(hChildOutInh), "Closing handle\n");
1681 
1682     msg_len = strlen(msg) + 1;
1683     ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1684     ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1685     memset(buffer, 0, sizeof(buffer));
1686     ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1687     ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1688 
1689     /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1690     ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1691 
1692     /* wait for child to terminate */
1693     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1694     /* child process has changed result file, so let profile functions know about it */
1695     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1696 
1697     okChildString("StdHandle", "msg", msg);
1698 
1699     release_memory();
1700     DeleteFileA(resfile);
1701 }
1702 
1703 static  void    test_ExitCode(void)
1704 {
1705     char                buffer[MAX_PATH];
1706     PROCESS_INFORMATION	info;
1707     STARTUPINFOA	startup;
1708     DWORD               code;
1709 
1710     /* let's start simplistic */
1711     memset(&startup, 0, sizeof(startup));
1712     startup.cb = sizeof(startup);
1713     startup.dwFlags = STARTF_USESHOWWINDOW;
1714     startup.wShowWindow = SW_SHOWNORMAL;
1715 
1716     get_file_name(resfile);
1717     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile);
1718     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1719 
1720     /* wait for child to terminate */
1721     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1722     /* child process has changed result file, so let profile functions know about it */
1723     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1724 
1725     ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1726     okChildInt("ExitCode", "value", code);
1727 
1728     release_memory();
1729     DeleteFileA(resfile);
1730 }
1731 
1732 static void test_OpenProcess(void)
1733 {
1734     HANDLE hproc;
1735     void *addr1;
1736     MEMORY_BASIC_INFORMATION info;
1737     SIZE_T dummy, read_bytes;
1738     BOOL ret;
1739 
1740     /* not exported in all windows versions */
1741     if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1742         win_skip("VirtualAllocEx not found\n");
1743         return;
1744     }
1745 
1746     /* without PROCESS_VM_OPERATION */
1747     hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1748     ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1749 
1750     SetLastError(0xdeadbeef);
1751     addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1752     ok(!addr1, "VirtualAllocEx should fail\n");
1753     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1754     {   /* Win9x */
1755         CloseHandle(hproc);
1756         win_skip("VirtualAllocEx not implemented\n");
1757         return;
1758     }
1759     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1760 
1761     read_bytes = 0xdeadbeef;
1762     SetLastError(0xdeadbeef);
1763     ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes);
1764     ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1765     ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1766 
1767     CloseHandle(hproc);
1768 
1769     hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1770     ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1771 
1772     addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1773     ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1774 
1775     /* without PROCESS_QUERY_INFORMATION */
1776     SetLastError(0xdeadbeef);
1777     ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1778        "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1779     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1780 
1781     /* without PROCESS_VM_READ */
1782     read_bytes = 0xdeadbeef;
1783     SetLastError(0xdeadbeef);
1784     ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1785        "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1786     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1787     ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1788 
1789     CloseHandle(hproc);
1790 
1791     hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1792 
1793     memset(&info, 0xcc, sizeof(info));
1794     read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1795     ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1796 
1797     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1798     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1799     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1800     ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1801     ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1802     /* NT reports Protect == 0 for a not committed memory block */
1803     ok(info.Protect == 0 /* NT */ ||
1804        info.Protect == PAGE_NOACCESS, /* Win9x */
1805         "%x != PAGE_NOACCESS\n", info.Protect);
1806     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1807 
1808     SetLastError(0xdeadbeef);
1809     ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1810        "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1811     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1812 
1813     CloseHandle(hproc);
1814 
1815     hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1816     if (hproc)
1817     {
1818         SetLastError(0xdeadbeef);
1819         memset(&info, 0xcc, sizeof(info));
1820         read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1821         if (read_bytes) /* win8 */
1822         {
1823             ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1824             ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1825             ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1826             ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1827             ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1828             ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1829             ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
1830             ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1831         }
1832         else /* before win8 */
1833             ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1834 
1835         SetLastError(0xdeadbeef);
1836         ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1837            "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1838         ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1839 
1840         CloseHandle(hproc);
1841     }
1842 
1843     ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1844 }
1845 
1846 static void test_GetProcessVersion(void)
1847 {
1848     static char cmdline[] = "winver.exe";
1849     PROCESS_INFORMATION pi;
1850     STARTUPINFOA si;
1851     DWORD ret;
1852 
1853     SetLastError(0xdeadbeef);
1854     ret = GetProcessVersion(0);
1855     ok(ret, "GetProcessVersion error %u\n", GetLastError());
1856 
1857     SetLastError(0xdeadbeef);
1858     ret = GetProcessVersion(GetCurrentProcessId());
1859     ok(ret, "GetProcessVersion error %u\n", GetLastError());
1860 
1861     memset(&si, 0, sizeof(si));
1862     si.cb = sizeof(si);
1863     si.dwFlags = STARTF_USESHOWWINDOW;
1864     si.wShowWindow = SW_HIDE;
1865     SetLastError(0xdeadbeef);
1866     ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1867     ok(ret, "CreateProcess error %u\n", GetLastError());
1868 
1869     SetLastError(0xdeadbeef);
1870     ret = GetProcessVersion(pi.dwProcessId);
1871     ok(ret, "GetProcessVersion error %u\n", GetLastError());
1872 
1873     SetLastError(0xdeadbeef);
1874     ret = TerminateProcess(pi.hProcess, 0);
1875     ok(ret, "TerminateProcess error %u\n", GetLastError());
1876 
1877     CloseHandle(pi.hProcess);
1878     CloseHandle(pi.hThread);
1879 }
1880 
1881 static void test_GetProcessImageFileNameA(void)
1882 {
1883     DWORD rc;
1884     CHAR process[MAX_PATH];
1885     static const char harddisk[] = "\\Device\\HarddiskVolume";
1886 
1887     if (!pK32GetProcessImageFileNameA)
1888     {
1889         win_skip("K32GetProcessImageFileNameA is unavailable\n");
1890         return;
1891     }
1892 
1893     /* callers must guess the buffer size */
1894     SetLastError(0xdeadbeef);
1895     rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1896     ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1897        "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError());
1898 
1899     *process = '\0';
1900     rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1901     expect_eq_d(rc, lstrlenA(process));
1902     if (strncmp(process, harddisk, lstrlenA(harddisk)))
1903     {
1904         todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1905         return;
1906     }
1907 
1908     if (!pQueryFullProcessImageNameA)
1909         win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1910     else
1911     {
1912         CHAR image[MAX_PATH];
1913         DWORD length;
1914 
1915         length = sizeof(image);
1916         expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1917         expect_eq_d(length, lstrlenA(image));
1918         ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1919     }
1920 }
1921 
1922 static void test_QueryFullProcessImageNameA(void)
1923 {
1924 #define INIT_STR "Just some words"
1925     DWORD length, size;
1926     CHAR buf[MAX_PATH], module[MAX_PATH];
1927 
1928     if (!pQueryFullProcessImageNameA)
1929     {
1930         win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1931         return;
1932     }
1933 
1934     *module = '\0';
1935     SetLastError(0); /* old Windows don't reset it on success */
1936     size = GetModuleFileNameA(NULL, module, sizeof(module));
1937     ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError());
1938 
1939     /* get the buffer length without \0 terminator */
1940     length = sizeof(buf);
1941     expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1942     expect_eq_d(length, lstrlenA(buf));
1943     ok((buf[0] == '\\' && buf[1] == '\\') ||
1944        lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1945 
1946     /*  when the buffer is too small
1947      *  - function fail with error ERROR_INSUFFICIENT_BUFFER
1948      *  - the size variable is not modified
1949      * tested with the biggest too small size
1950      */
1951     size = length;
1952     sprintf(buf,INIT_STR);
1953     expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1954     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1955     expect_eq_d(length, size);
1956     expect_eq_s(INIT_STR, buf);
1957 
1958     /* retest with smaller buffer size
1959      */
1960     size = 4;
1961     sprintf(buf,INIT_STR);
1962     expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1963     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1964     expect_eq_d(4, size);
1965     expect_eq_s(INIT_STR, buf);
1966 
1967     /* this is a difference between the ascii and the unicode version
1968      * the unicode version crashes when the size is big enough to hold
1969      * the result while the ascii version throws an error
1970      */
1971     size = 1024;
1972     expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1973     expect_eq_d(1024, size);
1974     expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
1975 }
1976 
1977 static void test_QueryFullProcessImageNameW(void)
1978 {
1979     HANDLE hSelf;
1980     WCHAR module_name[1024], device[1024];
1981     WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
1982     WCHAR buf[1024];
1983     DWORD size, len;
1984 
1985     if (!pQueryFullProcessImageNameW)
1986     {
1987         win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1988         return;
1989     }
1990 
1991     ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1992 
1993     /* GetCurrentProcess pseudo-handle */
1994     size = sizeof(buf) / sizeof(buf[0]);
1995     expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
1996     expect_eq_d(lstrlenW(buf), size);
1997     expect_eq_ws_i(buf, module_name);
1998 
1999     hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
2000     /* Real handle */
2001     size = sizeof(buf) / sizeof(buf[0]);
2002     expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2003     expect_eq_d(lstrlenW(buf), size);
2004     expect_eq_ws_i(buf, module_name);
2005 
2006     /* Buffer too small */
2007     size = lstrlenW(module_name)/2;
2008     lstrcpyW(buf, deviceW);
2009     SetLastError(0xdeadbeef);
2010     expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2011     expect_eq_d(lstrlenW(module_name)/2, size);  /* size not changed(!) */
2012     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2013     expect_eq_ws_i(deviceW, buf);  /* buffer not changed */
2014 
2015     /* Too small - not space for NUL terminator */
2016     size = lstrlenW(module_name);
2017     SetLastError(0xdeadbeef);
2018     expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2019     expect_eq_d(lstrlenW(module_name), size);  /* size not changed(!) */
2020     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2021 
2022     /* NULL buffer */
2023     size = 0;
2024     expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
2025     expect_eq_d(0, size);
2026     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2027 
2028     /* Buffer too small */
2029     size = lstrlenW(module_name)/2;
2030     SetLastError(0xdeadbeef);
2031     lstrcpyW(buf, module_name);
2032     expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2033     expect_eq_d(lstrlenW(module_name)/2, size);  /* size not changed(!) */
2034     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2035     expect_eq_ws_i(module_name, buf);  /* buffer not changed */
2036 
2037 
2038     /* native path */
2039     size = sizeof(buf) / sizeof(buf[0]);
2040     expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2041     expect_eq_d(lstrlenW(buf), size);
2042     ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2043     ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2044 
2045     module_name[2] = '\0';
2046     *device = '\0';
2047     size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0]));
2048     ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2049     len = lstrlenW(device);
2050     ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2051 
2052     if (size >= lstrlenW(buf))
2053     {
2054         ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2055     }
2056     else
2057     {
2058         ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2059         buf[len] = '\0';
2060         ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2061         ok(lstrcmpiW(module_name+3, buf+len+1) == 0, "expected '%s' to match '%s'\n", wine_dbgstr_w(module_name+3), wine_dbgstr_w(buf+len+1));
2062     }
2063 
2064     CloseHandle(hSelf);
2065 }
2066 
2067 static void test_Handles(void)
2068 {
2069     HANDLE handle = GetCurrentProcess();
2070     HANDLE h2, h3;
2071     BOOL ret;
2072     DWORD code;
2073 
2074     ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2075         handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2076         "invalid current process handle %p\n", handle );
2077     ret = GetExitCodeProcess( handle, &code );
2078     ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2079 #ifdef _WIN64
2080     /* truncated handle */
2081     SetLastError( 0xdeadbeef );
2082     handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2083     ret = GetExitCodeProcess( handle, &code );
2084     ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2085     ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2086     /* sign-extended handle */
2087     SetLastError( 0xdeadbeef );
2088     handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle);
2089     ret = GetExitCodeProcess( handle, &code );
2090     ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2091     /* invalid high-word */
2092     SetLastError( 0xdeadbeef );
2093     handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2094     ret = GetExitCodeProcess( handle, &code );
2095     ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2096     ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2097 #endif
2098 
2099     handle = GetStdHandle( STD_ERROR_HANDLE );
2100     ok( handle != 0, "handle %p\n", handle );
2101     DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &h3,
2102                      0, TRUE, DUPLICATE_SAME_ACCESS );
2103     SetStdHandle( STD_ERROR_HANDLE, h3 );
2104     CloseHandle( (HANDLE)STD_ERROR_HANDLE );
2105     h2 = GetStdHandle( STD_ERROR_HANDLE );
2106     ok( h2 == 0 ||
2107         broken( h2 == h3) || /* nt4, w2k */
2108         broken( h2 == INVALID_HANDLE_VALUE),  /* win9x */
2109         "wrong handle %p/%p\n", h2, h3 );
2110     SetStdHandle( STD_ERROR_HANDLE, handle );
2111 }
2112 
2113 static void test_IsWow64Process(void)
2114 {
2115     PROCESS_INFORMATION pi;
2116     STARTUPINFOA si;
2117     DWORD ret;
2118     BOOL is_wow64;
2119     static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2120     static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2121 
2122     if (!pIsWow64Process)
2123     {
2124         skip("IsWow64Process is not available\n");
2125         return;
2126     }
2127 
2128     memset(&si, 0, sizeof(si));
2129     si.cb = sizeof(si);
2130     si.dwFlags = STARTF_USESHOWWINDOW;
2131     si.wShowWindow = SW_HIDE;
2132     ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2133     if (ret)
2134     {
2135         trace("Created process %s\n", cmdline_wow64);
2136         is_wow64 = FALSE;
2137         ret = pIsWow64Process(pi.hProcess, &is_wow64);
2138         ok(ret, "IsWow64Process failed.\n");
2139         ok(is_wow64, "is_wow64 returned FALSE.\n");
2140 
2141         ret = TerminateProcess(pi.hProcess, 0);
2142         ok(ret, "TerminateProcess error\n");
2143 
2144         CloseHandle(pi.hProcess);
2145         CloseHandle(pi.hThread);
2146     }
2147 
2148     memset(&si, 0, sizeof(si));
2149     si.cb = sizeof(si);
2150     si.dwFlags = STARTF_USESHOWWINDOW;
2151     si.wShowWindow = SW_HIDE;
2152     ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2153     if (ret)
2154     {
2155         trace("Created process %s\n", cmdline);
2156         is_wow64 = TRUE;
2157         ret = pIsWow64Process(pi.hProcess, &is_wow64);
2158         ok(ret, "IsWow64Process failed.\n");
2159         ok(!is_wow64, "is_wow64 returned TRUE.\n");
2160 
2161         ret = TerminateProcess(pi.hProcess, 0);
2162         ok(ret, "TerminateProcess error\n");
2163 
2164         CloseHandle(pi.hProcess);
2165         CloseHandle(pi.hThread);
2166     }
2167 }
2168 
2169 static void test_SystemInfo(void)
2170 {
2171     SYSTEM_INFO si, nsi;
2172     BOOL is_wow64;
2173 
2174     if (!pGetNativeSystemInfo)
2175     {
2176         win_skip("GetNativeSystemInfo is not available\n");
2177         return;
2178     }
2179 
2180     if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2181 
2182     GetSystemInfo(&si);
2183     pGetNativeSystemInfo(&nsi);
2184     if (is_wow64)
2185     {
2186         if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2187         {
2188             ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2189                "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2190                S(U(nsi)).wProcessorArchitecture);
2191             ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664,
2192                "Expected PROCESSOR_AMD_X8664, got %d\n",
2193                nsi.dwProcessorType);
2194         }
2195     }
2196     else
2197     {
2198         ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2199            "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2200            S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2201         ok(si.dwProcessorType == nsi.dwProcessorType,
2202            "Expected no difference for dwProcessorType, got %d and %d\n",
2203            si.dwProcessorType, nsi.dwProcessorType);
2204     }
2205 }
2206 
2207 static void test_RegistryQuota(void)
2208 {
2209     BOOL ret;
2210     DWORD max_quota, used_quota;
2211 
2212     if (!pGetSystemRegistryQuota)
2213     {
2214         win_skip("GetSystemRegistryQuota is not available\n");
2215         return;
2216     }
2217 
2218     ret = pGetSystemRegistryQuota(NULL, NULL);
2219     ok(ret == TRUE,
2220        "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2221 
2222     ret = pGetSystemRegistryQuota(&max_quota, NULL);
2223     ok(ret == TRUE,
2224        "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2225 
2226     ret = pGetSystemRegistryQuota(NULL, &used_quota);
2227     ok(ret == TRUE,
2228        "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2229 
2230     ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2231     ok(ret == TRUE,
2232        "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2233 }
2234 
2235 static void test_TerminateProcess(void)
2236 {
2237     static char cmdline[] = "winver.exe";
2238     PROCESS_INFORMATION pi;
2239     STARTUPINFOA si;
2240     DWORD ret;
2241     HANDLE dummy, thread;
2242 
2243     memset(&si, 0, sizeof(si));
2244     si.cb = sizeof(si);
2245     SetLastError(0xdeadbeef);
2246     ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2247     ok(ret, "CreateProcess error %u\n", GetLastError());
2248 
2249     SetLastError(0xdeadbeef);
2250     thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2251     ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2252 
2253     /* create a not closed thread handle duplicate in the target process */
2254     SetLastError(0xdeadbeef);
2255     ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy,
2256                           0, FALSE, DUPLICATE_SAME_ACCESS);
2257     ok(ret, "DuplicateHandle error %u\n", GetLastError());
2258 
2259     SetLastError(0xdeadbeef);
2260     ret = TerminateThread(thread, 0);
2261     ok(ret, "TerminateThread error %u\n", GetLastError());
2262     CloseHandle(thread);
2263 
2264     SetLastError(0xdeadbeef);
2265     ret = TerminateProcess(pi.hProcess, 0);
2266     ok(ret, "TerminateProcess error %u\n", GetLastError());
2267 
2268     CloseHandle(pi.hProcess);
2269     CloseHandle(pi.hThread);
2270 }
2271 
2272 static void test_DuplicateHandle(void)
2273 {
2274     char path[MAX_PATH], file_name[MAX_PATH];
2275     HANDLE f, fmin, out;
2276     DWORD info;
2277     BOOL r;
2278 
2279     r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2280             GetCurrentProcess(), &out, 0, FALSE,
2281             DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2282     ok(r, "DuplicateHandle error %u\n", GetLastError());
2283     r = GetHandleInformation(out, &info);
2284     ok(r, "GetHandleInformation error %u\n", GetLastError());
2285     ok(info == 0, "info = %x\n", info);
2286     ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2287     CloseHandle(out);
2288 
2289     r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2290             GetCurrentProcess(), &out, 0, TRUE,
2291             DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2292     ok(r, "DuplicateHandle error %u\n", GetLastError());
2293     r = GetHandleInformation(out, &info);
2294     ok(r, "GetHandleInformation error %u\n", GetLastError());
2295     ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2296     ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2297     CloseHandle(out);
2298 
2299     GetTempPathA(MAX_PATH, path);
2300     GetTempFileNameA(path, "wt", 0, file_name);
2301     f = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2302     if (f == INVALID_HANDLE_VALUE)
2303     {
2304         ok(0, "could not create %s\n", file_name);
2305         return;
2306     }
2307 
2308     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2309             0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2310     ok(r, "DuplicateHandle error %u\n", GetLastError());
2311     ok(f == out, "f != out\n");
2312     r = GetHandleInformation(out, &info);
2313     ok(r, "GetHandleInformation error %u\n", GetLastError());
2314     ok(info == 0, "info = %x\n", info);
2315 
2316     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2317             0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2318     ok(r, "DuplicateHandle error %u\n", GetLastError());
2319     ok(f == out, "f != out\n");
2320     r = GetHandleInformation(out, &info);
2321     ok(r, "GetHandleInformation error %u\n", GetLastError());
2322     ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2323 
2324     r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
2325     ok(r, "SetHandleInformation error %u\n", GetLastError());
2326     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2327                 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2328     ok(r, "DuplicateHandle error %u\n", GetLastError());
2329     ok(f != out, "f == out\n");
2330     r = GetHandleInformation(out, &info);
2331     ok(r, "GetHandleInformation error %u\n", GetLastError());
2332     ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2333     r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2334     ok(r, "SetHandleInformation error %u\n", GetLastError());
2335 
2336     /* Test if DuplicateHandle allocates first free handle */
2337     if (f > out)
2338     {
2339         fmin = out;
2340     }
2341     else
2342     {
2343         fmin = f;
2344         f = out;
2345     }
2346     CloseHandle(fmin);
2347     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2348             0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2349     ok(r, "DuplicateHandle error %u\n", GetLastError());
2350     ok(f == out, "f != out\n");
2351     CloseHandle(out);
2352     DeleteFileA(file_name);
2353 
2354     f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2355     if (!is_console(f))
2356     {
2357         skip("DuplicateHandle on console handle\n");
2358         CloseHandle(f);
2359         return;
2360     }
2361 
2362     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2363             0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2364     ok(r, "DuplicateHandle error %u\n", GetLastError());
2365     todo_wine ok(f != out, "f == out\n");
2366     CloseHandle(out);
2367 }
2368 
2369 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2370 static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2371 {
2372     LPOVERLAPPED overlapped;
2373     ULONG_PTR value;
2374     DWORD key;
2375     BOOL ret;
2376 
2377     ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait);
2378 
2379     ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
2380     if (ret)
2381     {
2382         ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key);
2383         ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2384         ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2385     }
2386 }
2387 
2388 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2389 static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2390 {
2391     BOOL ret;
2392     char buffer[MAX_PATH];
2393     STARTUPINFOA si = {0};
2394 
2395     sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command);
2396 
2397     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2398     ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError());
2399 }
2400 
2401 #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
2402 static void _test_assigned_proc(int line, HANDLE job, int expected_count, ...)
2403 {
2404     char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20];
2405     PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2406     DWORD ret_len, pid;
2407     va_list valist;
2408     int n;
2409     BOOL ret;
2410 
2411     memset(buf, 0, sizeof(buf));
2412     ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2413     ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2414     if (ret)
2415     {
2416         todo_wine_if(expected_count)
2417         ok_(__FILE__, line)(expected_count == pid_list->NumberOfAssignedProcesses,
2418                             "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n",
2419                             expected_count, pid_list->NumberOfAssignedProcesses);
2420         todo_wine_if(expected_count)
2421         ok_(__FILE__, line)(expected_count == pid_list->NumberOfProcessIdsInList,
2422                             "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n",
2423                             expected_count, pid_list->NumberOfProcessIdsInList);
2424 
2425         va_start(valist, expected_count);
2426         for (n = 0; n < min(expected_count, pid_list->NumberOfProcessIdsInList); ++n)
2427         {
2428             pid = va_arg(valist, DWORD);
2429             ok_(__FILE__, line)(pid == pid_list->ProcessIdList[n],
2430                                 "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n",
2431                                 n, pid, pid_list->ProcessIdList[n]);
2432         }
2433         va_end(valist);
2434     }
2435 }
2436 
2437 #define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc)
2438 static void _test_accounting(int line, HANDLE job, int total_proc, int active_proc, int terminated_proc)
2439 {
2440     JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting;
2441     DWORD ret_len;
2442     BOOL ret;
2443 
2444     memset(&basic_accounting, 0, sizeof(basic_accounting));
2445     ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting, sizeof(basic_accounting), &ret_len);
2446     ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2447     if (ret)
2448     {
2449         /* Not going to check process times or page faults */
2450 
2451         todo_wine_if(total_proc)
2452         ok_(__FILE__, line)(total_proc == basic_accounting.TotalProcesses,
2453                             "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n",
2454                             total_proc, basic_accounting.TotalProcesses);
2455         todo_wine_if(active_proc)
2456         ok_(__FILE__, line)(active_proc == basic_accounting.ActiveProcesses,
2457                             "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n",
2458                             active_proc, basic_accounting.ActiveProcesses);
2459         ok_(__FILE__, line)(terminated_proc == basic_accounting.TotalTerminatedProcesses,
2460                             "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n",
2461                             terminated_proc, basic_accounting.TotalTerminatedProcesses);
2462     }
2463 }
2464 
2465 static void test_IsProcessInJob(void)
2466 {
2467     HANDLE job, job2;
2468     PROCESS_INFORMATION pi;
2469     BOOL ret, out;
2470     DWORD dwret;
2471 
2472     if (!pIsProcessInJob)
2473     {
2474         win_skip("IsProcessInJob not available.\n");
2475         return;
2476     }
2477 
2478     job = pCreateJobObjectW(NULL, NULL);
2479     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2480 
2481     job2 = pCreateJobObjectW(NULL, NULL);
2482     ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError());
2483 
2484     create_process("wait", &pi);
2485 
2486     out = TRUE;
2487     ret = pIsProcessInJob(pi.hProcess, job, &out);
2488     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2489     ok(!out, "IsProcessInJob returned out=%u\n", out);
2490     test_assigned_proc(job, 0);
2491     test_accounting(job, 0, 0, 0);
2492 
2493     out = TRUE;
2494     ret = pIsProcessInJob(pi.hProcess, job2, &out);
2495     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2496     ok(!out, "IsProcessInJob returned out=%u\n", out);
2497     test_assigned_proc(job2, 0);
2498     test_accounting(job2, 0, 0, 0);
2499 
2500     out = TRUE;
2501     ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2502     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2503     ok(!out, "IsProcessInJob returned out=%u\n", out);
2504 
2505     ret = pAssignProcessToJobObject(job, pi.hProcess);
2506     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2507 
2508     out = FALSE;
2509     ret = pIsProcessInJob(pi.hProcess, job, &out);
2510     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2511     ok(out, "IsProcessInJob returned out=%u\n", out);
2512     test_assigned_proc(job, 1, pi.dwProcessId);
2513     test_accounting(job, 1, 1, 0);
2514 
2515     out = TRUE;
2516     ret = pIsProcessInJob(pi.hProcess, job2, &out);
2517     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2518     ok(!out, "IsProcessInJob returned out=%u\n", out);
2519     test_assigned_proc(job2, 0);
2520     test_accounting(job2, 0, 0, 0);
2521 
2522     out = FALSE;
2523     ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2524     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2525     ok(out, "IsProcessInJob returned out=%u\n", out);
2526 
2527     TerminateProcess(pi.hProcess, 0);
2528 
2529     dwret = WaitForSingleObject(pi.hProcess, 1000);
2530     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2531 
2532     out = FALSE;
2533     ret = pIsProcessInJob(pi.hProcess, job, &out);
2534     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2535     ok(out, "IsProcessInJob returned out=%u\n", out);
2536     test_assigned_proc(job, 0);
2537     test_accounting(job, 1, 0, 0);
2538 
2539     CloseHandle(pi.hProcess);
2540     CloseHandle(pi.hThread);
2541     CloseHandle(job);
2542     CloseHandle(job2);
2543 }
2544 
2545 static void test_TerminateJobObject(void)
2546 {
2547     HANDLE job;
2548     PROCESS_INFORMATION pi;
2549     BOOL ret;
2550     DWORD dwret;
2551 
2552     job = pCreateJobObjectW(NULL, NULL);
2553     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2554     test_assigned_proc(job, 0);
2555     test_accounting(job, 0, 0, 0);
2556 
2557     create_process("wait", &pi);
2558 
2559     ret = pAssignProcessToJobObject(job, pi.hProcess);
2560     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2561     test_assigned_proc(job, 1, pi.dwProcessId);
2562     test_accounting(job, 1, 1, 0);
2563 
2564     ret = pTerminateJobObject(job, 123);
2565     ok(ret, "TerminateJobObject error %u\n", GetLastError());
2566 
2567     dwret = WaitForSingleObject(pi.hProcess, 1000);
2568     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2569     if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2570     test_assigned_proc(job, 0);
2571     test_accounting(job, 1, 0, 0);
2572 
2573     ret = GetExitCodeProcess(pi.hProcess, &dwret);
2574     ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
2575     ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
2576        "wrong exitcode %u\n", dwret);
2577 
2578     CloseHandle(pi.hProcess);
2579     CloseHandle(pi.hThread);
2580 
2581     /* Test adding an already terminated process to a job object */
2582     create_process("exit", &pi);
2583 
2584     dwret = WaitForSingleObject(pi.hProcess, 1000);
2585     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2586 
2587     SetLastError(0xdeadbeef);
2588     ret = pAssignProcessToJobObject(job, pi.hProcess);
2589     ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2590     expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2591     test_assigned_proc(job, 0);
2592     test_accounting(job, 1, 0, 0);
2593 
2594     CloseHandle(pi.hProcess);
2595     CloseHandle(pi.hThread);
2596 
2597     CloseHandle(job);
2598 }
2599 
2600 static void test_QueryInformationJobObject(void)
2601 {
2602     char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2603     PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2604     JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2605     JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2606     DWORD dwret, ret_len;
2607     PROCESS_INFORMATION pi[2];
2608     HANDLE job;
2609     BOOL ret;
2610 
2611     job = pCreateJobObjectW(NULL, NULL);
2612     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2613 
2614     /* Only active processes are returned */
2615     create_process("exit", &pi[0]);
2616     ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2617     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2618     dwret = WaitForSingleObject(pi[0].hProcess, 1000);
2619     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2620 
2621     CloseHandle(pi[0].hProcess);
2622     CloseHandle(pi[0].hThread);
2623 
2624     create_process("wait", &pi[0]);
2625     ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2626     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2627 
2628     create_process("wait", &pi[1]);
2629     ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2630     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2631 
2632     SetLastError(0xdeadbeef);
2633     ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2634                                     FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len);
2635     ok(!ret, "QueryInformationJobObject expected failure\n");
2636     expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2637 
2638     SetLastError(0xdeadbeef);
2639     memset(buf, 0, sizeof(buf));
2640     pid_list->NumberOfAssignedProcesses = 42;
2641     pid_list->NumberOfProcessIdsInList  = 42;
2642     ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2643                                     FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len);
2644     todo_wine
2645     ok(!ret, "QueryInformationJobObject expected failure\n");
2646     todo_wine
2647     expect_eq_d(ERROR_MORE_DATA, GetLastError());
2648     if (ret)
2649     {
2650         todo_wine
2651         expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2652         todo_wine
2653         expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2654     }
2655 
2656     memset(buf, 0, sizeof(buf));
2657     ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2658     ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2659     if(ret)
2660     {
2661         if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2662             win_skip("Number of assigned processes broken on Win 8\n");
2663         else
2664         {
2665             ULONG_PTR *list = pid_list->ProcessIdList;
2666 
2667             todo_wine
2668             ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]),
2669                "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2670 
2671             todo_wine
2672             expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2673             todo_wine
2674             expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2675             todo_wine
2676             expect_eq_d(pi[0].dwProcessId, list[0]);
2677             todo_wine
2678             expect_eq_d(pi[1].dwProcessId, list[1]);
2679         }
2680     }
2681 
2682     /* test JobObjectBasicLimitInformation */
2683     ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2684                                      sizeof(*basic_limit_info) - 1, &ret_len);
2685     ok(!ret, "QueryInformationJobObject expected failure\n");
2686     expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2687 
2688     ret_len = 0xdeadbeef;
2689     memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2690     ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2691                                      sizeof(*basic_limit_info), &ret_len);
2692     ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2693     ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2694     expect_eq_d(0, basic_limit_info->LimitFlags);
2695 
2696     /* test JobObjectExtendedLimitInformation */
2697     ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2698                                      sizeof(ext_limit_info) - 1, &ret_len);
2699     ok(!ret, "QueryInformationJobObject expected failure\n");
2700     expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2701 
2702     ret_len = 0xdeadbeef;
2703     memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2704     ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2705                                      sizeof(ext_limit_info), &ret_len);
2706     ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2707     ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2708     expect_eq_d(0, basic_limit_info->LimitFlags);
2709 
2710     TerminateProcess(pi[0].hProcess, 0);
2711     CloseHandle(pi[0].hProcess);
2712     CloseHandle(pi[0].hThread);
2713 
2714     TerminateProcess(pi[1].hProcess, 0);
2715     CloseHandle(pi[1].hProcess);
2716     CloseHandle(pi[1].hThread);
2717 
2718     CloseHandle(job);
2719 }
2720 
2721 static void test_CompletionPort(void)
2722 {
2723     JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
2724     PROCESS_INFORMATION pi;
2725     HANDLE job, port;
2726     DWORD dwret;
2727     BOOL ret;
2728 
2729     job = pCreateJobObjectW(NULL, NULL);
2730     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2731 
2732     port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2733     ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
2734 
2735     port_info.CompletionKey = job;
2736     port_info.CompletionPort = port;
2737     ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2738     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2739 
2740     create_process("wait", &pi);
2741 
2742     ret = pAssignProcessToJobObject(job, pi.hProcess);
2743     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2744 
2745     test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2746 
2747     TerminateProcess(pi.hProcess, 0);
2748     dwret = WaitForSingleObject(pi.hProcess, 1000);
2749     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2750 
2751     test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2752     test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100);
2753 
2754     CloseHandle(pi.hProcess);
2755     CloseHandle(pi.hThread);
2756     CloseHandle(job);
2757     CloseHandle(port);
2758 }
2759 
2760 static void test_KillOnJobClose(void)
2761 {
2762     JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2763     PROCESS_INFORMATION pi;
2764     DWORD dwret;
2765     HANDLE job;
2766     BOOL ret;
2767 
2768     job = pCreateJobObjectW(NULL, NULL);
2769     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2770 
2771     limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
2772     ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2773     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2774     {
2775         win_skip("Kill on job close limit not available\n");
2776         return;
2777     }
2778     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2779     test_assigned_proc(job, 0);
2780     test_accounting(job, 0, 0, 0);
2781 
2782     create_process("wait", &pi);
2783 
2784     ret = pAssignProcessToJobObject(job, pi.hProcess);
2785     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2786     test_assigned_proc(job, 1, pi.dwProcessId);
2787     test_accounting(job, 1, 1, 0);
2788 
2789     CloseHandle(job);
2790 
2791     dwret = WaitForSingleObject(pi.hProcess, 1000);
2792     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2793     if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2794 
2795     CloseHandle(pi.hProcess);
2796     CloseHandle(pi.hThread);
2797 }
2798 
2799 static void test_WaitForJobObject(void)
2800 {
2801     HANDLE job;
2802     PROCESS_INFORMATION pi;
2803     BOOL ret;
2804     DWORD dwret;
2805 
2806     /* test waiting for a job object when the process is killed */
2807     job = pCreateJobObjectW(NULL, NULL);
2808     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2809 
2810     dwret = WaitForSingleObject(job, 100);
2811     ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2812 
2813     create_process("wait", &pi);
2814 
2815     ret = pAssignProcessToJobObject(job, pi.hProcess);
2816     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2817 
2818     dwret = WaitForSingleObject(job, 100);
2819     ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2820 
2821     ret = pTerminateJobObject(job, 123);
2822     ok(ret, "TerminateJobObject error %u\n", GetLastError());
2823 
2824     dwret = WaitForSingleObject(job, 500);
2825     ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2826        "WaitForSingleObject returned %u\n", dwret);
2827 
2828     if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2829     {
2830 #ifdef __REACTOS__
2831         if (!ret)
2832         {
2833             ok(0, "HACK: Killing process to speed up the test\n");
2834             TerminateProcess(pi.hProcess, 0);
2835         }
2836 #endif
2837         CloseHandle(pi.hProcess);
2838         CloseHandle(pi.hThread);
2839         CloseHandle(job);
2840         win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2841         return;
2842     }
2843 
2844     /* the object is not reset immediately */
2845     dwret = WaitForSingleObject(job, 100);
2846     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2847 
2848     CloseHandle(pi.hProcess);
2849     CloseHandle(pi.hThread);
2850 
2851     /* creating a new process doesn't reset the signalled state */
2852     create_process("wait", &pi);
2853 
2854     ret = pAssignProcessToJobObject(job, pi.hProcess);
2855     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2856 
2857     dwret = WaitForSingleObject(job, 100);
2858     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2859 
2860     ret = pTerminateJobObject(job, 123);
2861     ok(ret, "TerminateJobObject error %u\n", GetLastError());
2862 
2863     CloseHandle(pi.hProcess);
2864     CloseHandle(pi.hThread);
2865 
2866     CloseHandle(job);
2867 
2868     /* repeat the test, but this time the process terminates properly */
2869     job = pCreateJobObjectW(NULL, NULL);
2870     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2871 
2872     dwret = WaitForSingleObject(job, 100);
2873     ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2874 
2875     create_process("exit", &pi);
2876 
2877     ret = pAssignProcessToJobObject(job, pi.hProcess);
2878     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2879 
2880     dwret = WaitForSingleObject(job, 100);
2881     ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2882 
2883     CloseHandle(pi.hProcess);
2884     CloseHandle(pi.hThread);
2885     CloseHandle(job);
2886 }
2887 
2888 static HANDLE test_AddSelfToJob(void)
2889 {
2890     HANDLE job;
2891     BOOL ret;
2892 
2893     job = pCreateJobObjectW(NULL, NULL);
2894     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2895 
2896     ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2897     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2898     test_assigned_proc(job, 1, GetCurrentProcessId());
2899     test_accounting(job, 1, 1, 0);
2900 
2901     return job;
2902 }
2903 
2904 static void test_jobInheritance(HANDLE job)
2905 {
2906     char buffer[MAX_PATH];
2907     PROCESS_INFORMATION pi;
2908     STARTUPINFOA si = {0};
2909     DWORD dwret;
2910     BOOL ret, out;
2911 
2912     if (!pIsProcessInJob)
2913     {
2914         win_skip("IsProcessInJob not available.\n");
2915         return;
2916     }
2917 
2918     sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2919 
2920     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2921     ok(ret, "CreateProcessA error %u\n", GetLastError());
2922 
2923     out = FALSE;
2924     ret = pIsProcessInJob(pi.hProcess, job, &out);
2925     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2926     ok(out, "IsProcessInJob returned out=%u\n", out);
2927     test_assigned_proc(job, 2, GetCurrentProcessId(), pi.dwProcessId);
2928     test_accounting(job, 2, 2, 0);
2929 
2930     dwret = WaitForSingleObject(pi.hProcess, 1000);
2931     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2932 
2933     CloseHandle(pi.hProcess);
2934     CloseHandle(pi.hThread);
2935 }
2936 
2937 static void test_BreakawayOk(HANDLE job)
2938 {
2939     JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2940     PROCESS_INFORMATION pi;
2941     STARTUPINFOA si = {0};
2942     char buffer[MAX_PATH];
2943     BOOL ret, out;
2944     DWORD dwret;
2945 
2946     if (!pIsProcessInJob)
2947     {
2948         win_skip("IsProcessInJob not available.\n");
2949         return;
2950     }
2951 
2952     sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2953 
2954     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2955     ok(!ret, "CreateProcessA expected failure\n");
2956     expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2957     test_assigned_proc(job, 1, GetCurrentProcessId());
2958     test_accounting(job, 2, 1, 0);
2959 
2960     if (ret)
2961     {
2962         TerminateProcess(pi.hProcess, 0);
2963 
2964         dwret = WaitForSingleObject(pi.hProcess, 1000);
2965         ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2966 
2967         CloseHandle(pi.hProcess);
2968         CloseHandle(pi.hThread);
2969     }
2970 
2971     limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
2972     ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2973     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2974 
2975     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2976     ok(ret, "CreateProcessA error %u\n", GetLastError());
2977 
2978     ret = pIsProcessInJob(pi.hProcess, job, &out);
2979     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2980     ok(!out, "IsProcessInJob returned out=%u\n", out);
2981     test_assigned_proc(job, 1, GetCurrentProcessId());
2982     test_accounting(job, 2, 1, 0);
2983 
2984     dwret = WaitForSingleObject(pi.hProcess, 1000);
2985     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2986 
2987     CloseHandle(pi.hProcess);
2988     CloseHandle(pi.hThread);
2989 
2990     limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
2991     ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2992     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2993 
2994     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2995     ok(ret, "CreateProcess error %u\n", GetLastError());
2996 
2997     ret = pIsProcessInJob(pi.hProcess, job, &out);
2998     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2999     ok(!out, "IsProcessInJob returned out=%u\n", out);
3000     test_assigned_proc(job, 1, GetCurrentProcessId());
3001     test_accounting(job, 2, 1, 0);
3002 
3003     dwret = WaitForSingleObject(pi.hProcess, 1000);
3004     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
3005 
3006     CloseHandle(pi.hProcess);
3007     CloseHandle(pi.hThread);
3008 
3009     /* unset breakaway ok */
3010     limit_info.BasicLimitInformation.LimitFlags = 0;
3011     ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3012     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
3013 }
3014 
3015 static void test_StartupNoConsole(void)
3016 {
3017 #ifndef _WIN64
3018     char                buffer[MAX_PATH];
3019     STARTUPINFOA        startup;
3020     PROCESS_INFORMATION info;
3021 
3022     memset(&startup, 0, sizeof(startup));
3023     startup.cb = sizeof(startup);
3024     startup.dwFlags = STARTF_USESHOWWINDOW;
3025     startup.wShowWindow = SW_SHOWNORMAL;
3026     get_file_name(resfile);
3027     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3028     ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3029                       &info), "CreateProcess\n");
3030     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3031     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3032     okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3033     okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3034     okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3035     okChildInt("TEB", "hStdInput", 0);
3036     okChildInt("TEB", "hStdOutput", 0);
3037     okChildInt("TEB", "hStdError", 0);
3038     release_memory();
3039     DeleteFileA(resfile);
3040 #endif
3041 }
3042 
3043 static void test_DetachConsoleHandles(void)
3044 {
3045 #ifndef _WIN64
3046     char                buffer[MAX_PATH];
3047     STARTUPINFOA        startup;
3048     PROCESS_INFORMATION info;
3049     UINT                result;
3050 
3051     memset(&startup, 0, sizeof(startup));
3052     startup.cb = sizeof(startup);
3053     startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
3054     startup.wShowWindow = SW_SHOWNORMAL;
3055     startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
3056     startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
3057     startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
3058     get_file_name(resfile);
3059     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3060     ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3061                       &info), "CreateProcess\n");
3062     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3063     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3064 
3065     result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile);
3066     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3067     result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile);
3068     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3069     result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile);
3070     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3071     result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile);
3072     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3073     result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile);
3074     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3075     result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile);
3076     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3077 
3078     release_memory();
3079     DeleteFileA(resfile);
3080 #endif
3081 }
3082 
3083 #if defined(__i386__) || defined(__x86_64__)
3084 static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi,
3085                            IMAGE_NT_HEADERS *nt_header)
3086 {
3087     IMAGE_DOS_HEADER dos_header;
3088 
3089     if (!ReadProcessMemory(process_handle, mbi->BaseAddress, &dos_header, sizeof(dos_header), NULL))
3090         return FALSE;
3091 
3092     if ((dos_header.e_magic != IMAGE_DOS_SIGNATURE) ||
3093         ((ULONG)dos_header.e_lfanew > mbi->RegionSize) ||
3094         (dos_header.e_lfanew < sizeof(dos_header)))
3095         return FALSE;
3096 
3097     if (!ReadProcessMemory(process_handle, (char *)mbi->BaseAddress + dos_header.e_lfanew,
3098                            nt_header, sizeof(*nt_header), NULL))
3099         return FALSE;
3100 
3101     return (nt_header->Signature == IMAGE_NT_SIGNATURE);
3102 }
3103 
3104 static PVOID get_process_exe(HANDLE process_handle, IMAGE_NT_HEADERS *nt_header)
3105 {
3106     PVOID exe_base, address;
3107     MEMORY_BASIC_INFORMATION mbi;
3108 
3109     /* Find the EXE base in the new process */
3110     exe_base = NULL;
3111     for (address = NULL ;
3112          VirtualQueryEx(process_handle, address, &mbi, sizeof(mbi)) ;
3113          address = (char *)mbi.BaseAddress + mbi.RegionSize) {
3114         if ((mbi.Type == SEC_IMAGE) &&
3115             read_nt_header(process_handle, &mbi, nt_header) &&
3116             !(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
3117             exe_base = mbi.BaseAddress;
3118             break;
3119         }
3120     }
3121 
3122     return exe_base;
3123 }
3124 
3125 static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE_NT_HEADERS *nt_header)
3126 {
3127     BOOL ret;
3128     IMAGE_IMPORT_DESCRIPTOR iid;
3129     ULONG_PTR orig_iat_entry_value, iat_entry_value;
3130 
3131     ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, "Import table VA is zero\n");
3132     ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, "Import table Size is zero\n");
3133 
3134     if (!nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ||
3135         !nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
3136         return FALSE;
3137 
3138     /* Read the first IID */
3139     ret = ReadProcessMemory(process_handle,
3140                             (char *)module_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
3141                             &iid, sizeof(iid), NULL);
3142     ok(ret, "Failed to read remote module IID (%d)\n", GetLastError());
3143 
3144     /* Validate the IID is present and not a bound import, and that we have
3145        an OriginalFirstThunk to compare with */
3146     ok(iid.Name, "Module first IID does not have a Name\n");
3147     ok(iid.FirstThunk, "Module first IID does not have a FirstThunk\n");
3148     ok(!iid.TimeDateStamp, "Module first IID is a bound import (UNSUPPORTED for current test)\n");
3149     ok(iid.OriginalFirstThunk, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3150 
3151     /* Read a single IAT entry from the FirstThunk */
3152     ret = ReadProcessMemory(process_handle, (char *)module_base + iid.FirstThunk,
3153                             &iat_entry_value, sizeof(iat_entry_value), NULL);
3154     ok(ret, "Failed to read IAT entry from FirstThunk (%d)\n", GetLastError());
3155     ok(iat_entry_value, "IAT entry in FirstThunk is NULL\n");
3156 
3157     /* Read a single IAT entry from the OriginalFirstThunk */
3158     ret = ReadProcessMemory(process_handle, (char *)module_base + iid.OriginalFirstThunk,
3159                             &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL);
3160     ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%d)\n", GetLastError());
3161     ok(orig_iat_entry_value, "IAT entry in OriginalFirstThunk is NULL\n");
3162 
3163     return iat_entry_value != orig_iat_entry_value;
3164 }
3165 
3166 static void test_SuspendProcessNewThread(void)
3167 {
3168     BOOL ret;
3169     STARTUPINFOA si = {0};
3170     PROCESS_INFORMATION pi = {0};
3171     PVOID exe_base, exit_thread_ptr;
3172     IMAGE_NT_HEADERS nt_header;
3173     HANDLE thread_handle = NULL;
3174     DWORD dret, exit_code = 0;
3175     CONTEXT ctx;
3176 
3177     exit_thread_ptr = GetProcAddress(hkernel32, "ExitThread");
3178     ok(exit_thread_ptr != NULL, "GetProcAddress ExitThread failed\n");
3179 
3180     si.cb = sizeof(si);
3181     ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3182     ok(ret, "Failed to create process (%d)\n", GetLastError());
3183 
3184     exe_base = get_process_exe(pi.hProcess, &nt_header);
3185     ok(exe_base != NULL, "Could not find EXE in remote process\n");
3186 
3187     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3188     ok(!ret, "IAT entry resolved prematurely\n");
3189 
3190     thread_handle = CreateRemoteThread(pi.hProcess, NULL, 0,
3191                                        (LPTHREAD_START_ROUTINE)exit_thread_ptr,
3192                                        (PVOID)(ULONG_PTR)0x1234, CREATE_SUSPENDED, NULL);
3193     ok(thread_handle != NULL, "Could not create remote thread (%d)\n", GetLastError());
3194 
3195     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3196     ok(!ret, "IAT entry resolved prematurely\n");
3197 
3198     ctx.ContextFlags = CONTEXT_ALL;
3199     ret = GetThreadContext( thread_handle, &ctx );
3200     ok( ret, "Failed retrieving remote thread context (%d)\n", GetLastError() );
3201     ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags );
3202 #ifdef __x86_64__
3203     ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax );
3204     ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx );
3205     ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %lx/%p\n", ctx.Rcx, exit_thread_ptr );
3206     ok( ctx.Rdx == 0x1234, "wrong rdx %lx\n", ctx.Rdx );
3207     ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi );
3208     ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi );
3209     ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp );
3210     ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 );
3211     ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 );
3212     ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 );
3213     ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 );
3214     ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 );
3215     ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 );
3216     ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 );
3217     ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 );
3218     ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp );
3219     ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags );
3220     ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr );
3221     ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3222 #else
3223     ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp );
3224     if (!ctx.Ebp)  /* winxp is completely different */
3225     {
3226         ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx );
3227         ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx );
3228         ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi );
3229         ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi );
3230     }
3231     ok( ctx.Eax == (ULONG_PTR)exit_thread_ptr, "wrong eax %08x/%p\n", ctx.Eax, exit_thread_ptr );
3232     ok( ctx.Ebx == 0x1234, "wrong ebx %08x\n", ctx.Ebx );
3233     ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3234         "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp );
3235     ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags );
3236     ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord );
3237     ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3238 #endif
3239 
3240     ResumeThread( thread_handle );
3241     dret = WaitForSingleObject(thread_handle, 60000);
3242     ok(dret == WAIT_OBJECT_0, "Waiting for remote thread failed (%d)\n", GetLastError());
3243     ret = GetExitCodeThread(thread_handle, &exit_code);
3244     ok(ret, "Failed to retrieve remote thread exit code (%d)\n", GetLastError());
3245     ok(exit_code == 0x1234, "Invalid remote thread exit code\n");
3246 
3247     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3248     ok(ret, "EXE IAT entry not resolved\n");
3249 
3250     if (thread_handle)
3251         CloseHandle(thread_handle);
3252 
3253     TerminateProcess(pi.hProcess, 0);
3254     WaitForSingleObject(pi.hProcess, 10000);
3255     CloseHandle(pi.hProcess);
3256     CloseHandle(pi.hThread);
3257 }
3258 
3259 static void test_SuspendProcessState(void)
3260 {
3261     struct pipe_params
3262     {
3263         ULONG pipe_write_buf;
3264         ULONG pipe_read_buf;
3265         ULONG bytes_returned;
3266         CHAR pipe_name[MAX_PATH];
3267     };
3268 
3269 #ifdef __x86_64__
3270     struct remote_rop_chain
3271     {
3272         void     *exit_process_ptr;
3273         ULONG_PTR home_rcx;
3274         ULONG_PTR home_rdx;
3275         ULONG_PTR home_r8;
3276         ULONG_PTR home_r9;
3277         ULONG_PTR pipe_read_buf_size;
3278         ULONG_PTR bytes_returned;
3279         ULONG_PTR timeout;
3280     };
3281 #else
3282     struct remote_rop_chain
3283     {
3284         void     *exit_process_ptr;
3285         ULONG_PTR pipe_name;
3286         ULONG_PTR pipe_write_buf;
3287         ULONG_PTR pipe_write_buf_size;
3288         ULONG_PTR pipe_read_buf;
3289         ULONG_PTR pipe_read_buf_size;
3290         ULONG_PTR bytes_returned;
3291         ULONG_PTR timeout;
3292         void     *unreached_ret;
3293         ULONG_PTR exit_code;
3294     };
3295 #endif
3296 
3297     static const char pipe_name[] = "\\\\.\\pipe\\TestPipe";
3298     static const ULONG pipe_write_magic = 0x454e4957;
3299     STARTUPINFOA si = {0};
3300     PROCESS_INFORMATION pi = {0};
3301     PVOID exe_base, remote_pipe_params, exit_process_ptr,
3302           call_named_pipe_a;
3303     IMAGE_NT_HEADERS nt_header;
3304     struct pipe_params pipe_params;
3305     struct remote_rop_chain rop_chain;
3306     CONTEXT ctx;
3307     HANDLE server_pipe_handle;
3308     BOOL pipe_connected;
3309     ULONG pipe_magic, numb;
3310     BOOL ret;
3311     void *entry_ptr, *peb_ptr;
3312     PEB child_peb;
3313 
3314     exit_process_ptr = GetProcAddress(hkernel32, "ExitProcess");
3315     ok(exit_process_ptr != NULL, "GetProcAddress ExitProcess failed\n");
3316 
3317     call_named_pipe_a = GetProcAddress(hkernel32, "CallNamedPipeA");
3318     ok(call_named_pipe_a != NULL, "GetProcAddress CallNamedPipeA failed\n");
3319 
3320     si.cb = sizeof(si);
3321     ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3322     ok(ret, "Failed to create process (%d)\n", GetLastError());
3323 
3324     exe_base = get_process_exe(pi.hProcess, &nt_header);
3325     /* Make sure we found the EXE in the new process */
3326     ok(exe_base != NULL, "Could not find EXE in remote process\n");
3327 
3328     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3329     ok(!ret, "IAT entry resolved prematurely\n");
3330 
3331     server_pipe_handle = CreateNamedPipeA(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH,
3332                                         PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0x20000, 0x20000,
3333                                         0, NULL);
3334     ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%d)\n", GetLastError());
3335 
3336     /* Set up the remote process environment */
3337     ctx.ContextFlags = CONTEXT_ALL;
3338     ret = GetThreadContext(pi.hThread, &ctx);
3339     ok(ret, "Failed retrieving remote thread context (%d)\n", GetLastError());
3340     ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags );
3341 
3342     remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE);
3343     ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%d)\n", GetLastError());
3344 
3345     pipe_params.pipe_write_buf = pipe_write_magic;
3346     pipe_params.pipe_read_buf = 0;
3347     pipe_params.bytes_returned = 0;
3348     strcpy(pipe_params.pipe_name, pipe_name);
3349 
3350     ret = WriteProcessMemory(pi.hProcess, remote_pipe_params,
3351                              &pipe_params, sizeof(pipe_params), NULL);
3352     ok(ret, "Failed to write to remote process memory (%d)\n", GetLastError());
3353 
3354 #ifdef __x86_64__
3355     ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax );
3356     ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx );
3357     ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi );
3358     ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi );
3359     ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp );
3360     ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 );
3361     ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 );
3362     ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 );
3363     ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 );
3364     ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 );
3365     ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 );
3366     ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 );
3367     ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 );
3368     ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp );
3369     ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags );
3370     ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr );
3371     ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3372     entry_ptr = (void *)ctx.Rcx;
3373     peb_ptr = (void *)ctx.Rdx;
3374 
3375     rop_chain.exit_process_ptr = exit_process_ptr;
3376     ctx.Rcx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3377     ctx.Rdx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3378     ctx.R8 = sizeof(pipe_params.pipe_write_buf);
3379     ctx.R9 = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3380     rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3381     rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3382     rop_chain.timeout = 10000;
3383 
3384     ctx.Rip = (ULONG_PTR)call_named_pipe_a;
3385     ctx.Rsp -= sizeof(rop_chain);
3386     ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL);
3387     ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3388 #else
3389     ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp );
3390     if (!ctx.Ebp)  /* winxp is completely different */
3391     {
3392         ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx );
3393         ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx );
3394         ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi );
3395         ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi );
3396     }
3397     ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3398         "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp );
3399     ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags );
3400     ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord );
3401     ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3402     entry_ptr = (void *)ctx.Eax;
3403     peb_ptr = (void *)ctx.Ebx;
3404 
3405     rop_chain.exit_process_ptr = exit_process_ptr;
3406     rop_chain.pipe_name = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3407     rop_chain.pipe_write_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3408     rop_chain.pipe_write_buf_size = sizeof(pipe_params.pipe_write_buf);
3409     rop_chain.pipe_read_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3410     rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3411     rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3412     rop_chain.timeout = 10000;
3413     rop_chain.exit_code = 0;
3414 
3415     ctx.Eip = (ULONG_PTR)call_named_pipe_a;
3416     ctx.Esp -= sizeof(rop_chain);
3417     ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Esp, &rop_chain, sizeof(rop_chain), NULL);
3418     ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3419 #endif
3420 
3421     ret = ReadProcessMemory( pi.hProcess, peb_ptr, &child_peb, sizeof(child_peb), NULL );
3422     ok( ret, "Failed to read PEB (%u)\n", GetLastError() );
3423     ok( child_peb.ImageBaseAddress == exe_base, "wrong base %p/%p\n",
3424         child_peb.ImageBaseAddress, exe_base );
3425     ok( entry_ptr == (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint,
3426         "wrong entry point %p/%p\n", entry_ptr,
3427         (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint );
3428 
3429     ret = SetThreadContext(pi.hThread, &ctx);
3430     ok(ret, "Failed to set remote thread context (%d)\n", GetLastError());
3431 
3432     ResumeThread(pi.hThread);
3433 
3434     pipe_connected = ConnectNamedPipe(server_pipe_handle, NULL) || (GetLastError() == ERROR_PIPE_CONNECTED);
3435     ok(pipe_connected, "Pipe did not connect\n");
3436 
3437     ret = ReadFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3438     ok(ret, "Failed to read buffer from pipe (%d)\n", GetLastError());
3439 
3440     ok(pipe_magic == pipe_write_magic, "Did not get the correct magic from the remote process\n");
3441 
3442     /* Validate the Imports, at this point the thread in the new process should have
3443        initialized the EXE module imports and call each dll DllMain notifying it on
3444        the new thread in the process. */
3445     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3446     ok(ret, "EXE IAT is not resolved\n");
3447 
3448     ret = WriteFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3449     ok(ret, "Failed to write the magic back to the pipe (%d)\n", GetLastError());
3450 
3451     CloseHandle(server_pipe_handle);
3452     TerminateProcess(pi.hProcess, 0);
3453     WaitForSingleObject(pi.hProcess, 10000);
3454     CloseHandle(pi.hProcess);
3455     CloseHandle(pi.hThread);
3456 }
3457 #else
3458 static void test_SuspendProcessNewThread(void)
3459 {
3460 }
3461 static void test_SuspendProcessState(void)
3462 {
3463 }
3464 #endif
3465 
3466 static void test_DetachStdHandles(void)
3467 {
3468 #ifndef _WIN64
3469     char                buffer[MAX_PATH], tempfile[MAX_PATH];
3470     STARTUPINFOA        startup;
3471     PROCESS_INFORMATION info;
3472     HANDLE              hstdin, hstdout, hstderr, htemp;
3473     BOOL                res;
3474 
3475     hstdin = GetStdHandle(STD_INPUT_HANDLE);
3476     hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
3477     hstderr = GetStdHandle(STD_ERROR_HANDLE);
3478 
3479     get_file_name(tempfile);
3480     htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3481     ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n");
3482 
3483     memset(&startup, 0, sizeof(startup));
3484     startup.cb = sizeof(startup);
3485     startup.dwFlags = STARTF_USESHOWWINDOW;
3486     startup.wShowWindow = SW_SHOWNORMAL;
3487     get_file_name(resfile);
3488     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3489 
3490     SetStdHandle(STD_INPUT_HANDLE, htemp);
3491     SetStdHandle(STD_OUTPUT_HANDLE, htemp);
3492     SetStdHandle(STD_ERROR_HANDLE, htemp);
3493 
3494     res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3495                       &info);
3496 
3497     SetStdHandle(STD_INPUT_HANDLE, hstdin);
3498     SetStdHandle(STD_OUTPUT_HANDLE, hstdout);
3499     SetStdHandle(STD_ERROR_HANDLE, hstderr);
3500 
3501     ok(res, "CreateProcess failed\n");
3502     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3503     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3504     okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3505     okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3506     okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3507     okChildInt("TEB", "hStdInput", 0);
3508     okChildInt("TEB", "hStdOutput", 0);
3509     okChildInt("TEB", "hStdError", 0);
3510     release_memory();
3511     DeleteFileA(resfile);
3512 
3513     CloseHandle(htemp);
3514     DeleteFileA(tempfile);
3515 #endif
3516 }
3517 
3518 static void test_GetNumaProcessorNode(void)
3519 {
3520     SYSTEM_INFO si;
3521     UCHAR node;
3522     BOOL ret;
3523     int i;
3524 
3525     if (!pGetNumaProcessorNode)
3526     {
3527         win_skip("GetNumaProcessorNode is missing\n");
3528         return;
3529     }
3530 
3531     GetSystemInfo(&si);
3532     for (i = 0; i < 256; i++)
3533     {
3534         SetLastError(0xdeadbeef);
3535         node = (i < si.dwNumberOfProcessors) ? 0xFF : 0xAA;
3536         ret = pGetNumaProcessorNode(i, &node);
3537         if (i < si.dwNumberOfProcessors)
3538         {
3539             ok(ret, "GetNumaProcessorNode returned FALSE for processor %d\n", i);
3540             ok(node != 0xFF, "expected node != 0xFF, but got 0xFF\n");
3541         }
3542         else
3543         {
3544             ok(!ret, "GetNumaProcessorNode returned TRUE for processor %d\n", i);
3545             ok(node == 0xFF || broken(node == 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node);
3546             ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3547         }
3548     }
3549 }
3550 
3551 static void test_session_info(void)
3552 {
3553     DWORD session_id, active_session;
3554     BOOL r;
3555 
3556     if (!pProcessIdToSessionId)
3557     {
3558         win_skip("ProcessIdToSessionId is missing\n");
3559         return;
3560     }
3561 
3562     r = pProcessIdToSessionId(GetCurrentProcessId(), &session_id);
3563     ok(r, "ProcessIdToSessionId failed: %u\n", GetLastError());
3564     trace("session_id = %x\n", session_id);
3565 
3566     active_session = pWTSGetActiveConsoleSessionId();
3567     trace("active_session = %x\n", active_session);
3568 }
3569 
3570 static void test_process_info(void)
3571 {
3572     char buf[4096];
3573     static const ULONG info_size[] =
3574     {
3575         sizeof(PROCESS_BASIC_INFORMATION) /* ProcessBasicInformation */,
3576         sizeof(QUOTA_LIMITS) /* ProcessQuotaLimits */,
3577         sizeof(IO_COUNTERS) /* ProcessIoCounters */,
3578         sizeof(VM_COUNTERS) /* ProcessVmCounters */,
3579         sizeof(KERNEL_USER_TIMES) /* ProcessTimes */,
3580         sizeof(ULONG) /* ProcessBasePriority */,
3581         sizeof(ULONG) /* ProcessRaisePriority */,
3582         sizeof(HANDLE) /* ProcessDebugPort */,
3583         sizeof(HANDLE) /* ProcessExceptionPort */,
3584         0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3585         0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3586         0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3587         sizeof(ULONG) /* ProcessDefaultHardErrorMode */,
3588         0 /* ProcessIoPortHandlers: kernel-mode only */,
3589         0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3590         0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3591         sizeof(ULONG) /* ProcessUserModeIOPL */,
3592         sizeof(BOOLEAN) /* ProcessEnableAlignmentFaultFixup */,
3593         sizeof(PROCESS_PRIORITY_CLASS) /* ProcessPriorityClass */,
3594         sizeof(ULONG) /* ProcessWx86Information */,
3595         sizeof(ULONG) /* ProcessHandleCount */,
3596         sizeof(ULONG_PTR) /* ProcessAffinityMask */,
3597         sizeof(ULONG) /* ProcessPriorityBoost */,
3598         0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3599         0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3600         0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3601         sizeof(ULONG_PTR) /* ProcessWow64Information */,
3602         sizeof(buf) /* ProcessImageFileName */,
3603         sizeof(ULONG) /* ProcessLUIDDeviceMapsEnabled */,
3604         sizeof(ULONG) /* ProcessBreakOnTermination */,
3605         sizeof(HANDLE) /* ProcessDebugObjectHandle */,
3606         sizeof(ULONG) /* ProcessDebugFlags */,
3607         sizeof(buf) /* ProcessHandleTracing */,
3608         sizeof(ULONG) /* ProcessIoPriority */,
3609         sizeof(ULONG) /* ProcessExecuteFlags */,
3610         0 /* FIXME: sizeof(?) ProcessTlsInformation */,
3611         0 /* FIXME: sizeof(?) ProcessCookie */,
3612         sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */,
3613         0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */,
3614         sizeof(ULONG) /* ProcessPagePriority */,
3615         40 /* ProcessInstrumentationCallback */,
3616         0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
3617         0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
3618         sizeof(buf) /* ProcessImageFileNameWin32 */,
3619         sizeof(HANDLE) /* ProcessImageFileMapping */,
3620         0 /* FIXME: sizeof(PROCESS_AFFINITY_UPDATE_MODE) ProcessAffinityUpdateMode */,
3621         0 /* FIXME: sizeof(PROCESS_MEMORY_ALLOCATION_MODE) ProcessMemoryAllocationMode */,
3622         sizeof(USHORT) /* ProcessGroupInformation */,
3623         sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */,
3624         sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */,
3625         0 /* FIXME: sizeof(PROCESS_WINDOW_INFORMATION) ProcessWindowInformation */,
3626 #if 0 /* FIXME: Add remaining classes */
3627         sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */,
3628         sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */,
3629         sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */,
3630         sizeof(?) /* ProcessHandleCheckingMode */,
3631         sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION) /* ProcessKeepAliveCount */,
3632         sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION) /* ProcessRevokeFileHandles */,
3633         sizeof(PROCESS_WORKING_SET_CONTROL) /* ProcessWorkingSetControl */,
3634         sizeof(?) /* ProcessHandleTable */,
3635         sizeof(?) /* ProcessCheckStackExtentsMode */,
3636         sizeof(buf) /* ProcessCommandLineInformation */,
3637         sizeof(PS_PROTECTION) /* ProcessProtectionInformation */,
3638         sizeof(PROCESS_MEMORY_EXHAUSTION_INFO) /* ProcessMemoryExhaustion */,
3639         sizeof(PROCESS_FAULT_INFORMATION) /* ProcessFaultInformation */,
3640         sizeof(PROCESS_TELEMETRY_ID_INFORMATION) /* ProcessTelemetryIdInformation */,
3641         sizeof(PROCESS_COMMIT_RELEASE_INFORMATION) /* ProcessCommitReleaseInformation */,
3642         sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3643         sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3644         0 /* ProcessReserved1Information */,
3645         0 /* ProcessReserved2Information */,
3646         sizeof(?) /* ProcessSubsystemProcess */,
3647         sizeof(PROCESS_JOB_MEMORY_INFO) /* ProcessJobMemoryInformation */,
3648 #endif
3649     };
3650     HANDLE hproc;
3651     ULONG i, status, ret_len, size;
3652 
3653     if (!pNtQueryInformationProcess)
3654     {
3655         win_skip("NtQueryInformationProcess is not available on this platform\n");
3656         return;
3657     }
3658 
3659     hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
3660     if (!hproc)
3661     {
3662         win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
3663         return;
3664     }
3665 
3666     for (i = 0; i < MaxProcessInfoClass; i++)
3667     {
3668         size = info_size[i];
3669         if (!size) size = sizeof(buf);
3670         ret_len = 0;
3671         status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len);
3672         if (status == STATUS_NOT_IMPLEMENTED) continue;
3673         if (status == STATUS_INVALID_INFO_CLASS) continue;
3674         if (status == STATUS_INFO_LENGTH_MISMATCH) continue;
3675 
3676         switch (i)
3677         {
3678         case ProcessBasicInformation:
3679         case ProcessQuotaLimits:
3680         case ProcessTimes:
3681         case ProcessPriorityClass:
3682         case ProcessPriorityBoost:
3683         case ProcessLUIDDeviceMapsEnabled:
3684         case 33 /* ProcessIoPriority */:
3685         case ProcessIoCounters:
3686         case ProcessVmCounters:
3687         case ProcessWow64Information:
3688         case ProcessDefaultHardErrorMode:
3689         case ProcessHandleCount:
3690         case ProcessImageFileName:
3691         case ProcessImageInformation:
3692         case ProcessPagePriority:
3693         case ProcessImageFileNameWin32:
3694             ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3695             break;
3696 
3697         case ProcessAffinityMask:
3698         case ProcessBreakOnTermination:
3699         case ProcessGroupInformation:
3700         case ProcessConsoleHostProcess:
3701             ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */,
3702                "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3703             break;
3704 
3705         case ProcessDebugObjectHandle:
3706             ok(status == STATUS_ACCESS_DENIED || status == STATUS_PORT_NOT_SET,
3707                "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3708             break;
3709 
3710         case ProcessExecuteFlags:
3711         case ProcessDebugPort:
3712         case ProcessDebugFlags:
3713         case ProcessCookie:
3714 todo_wine
3715             ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3716             break;
3717 
3718         default:
3719             ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3720             break;
3721         }
3722     }
3723 
3724     CloseHandle(hproc);
3725 }
3726 
3727 static void test_GetLogicalProcessorInformationEx(void)
3728 {
3729     SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info;
3730     DWORD len;
3731     BOOL ret;
3732 
3733     if (!pGetLogicalProcessorInformationEx)
3734     {
3735         win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3736         return;
3737     }
3738 
3739     ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, NULL);
3740     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
3741 
3742     len = 0;
3743     ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len);
3744     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3745     ok(len > 0, "got %u\n", len);
3746 
3747     len = 0;
3748     ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len);
3749     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3750     ok(len > 0, "got %u\n", len);
3751 
3752     info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
3753     ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len);
3754     ok(ret, "got %d, error %d\n", ret, GetLastError());
3755     ok(info->Size > 0, "got %u\n", info->Size);
3756     HeapFree(GetProcessHeap(), 0, info);
3757 }
3758 
3759 static void test_largepages(void)
3760 {
3761     SIZE_T size;
3762 
3763     if (!pGetLargePageMinimum) {
3764         skip("No GetLargePageMinimum support.\n");
3765         return;
3766     }
3767     size = pGetLargePageMinimum();
3768 
3769     ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size);
3770 }
3771 
3772 struct proc_thread_attr
3773 {
3774     DWORD_PTR attr;
3775     SIZE_T size;
3776     void *value;
3777 };
3778 
3779 struct _PROC_THREAD_ATTRIBUTE_LIST
3780 {
3781     DWORD mask;  /* bitmask of items in list */
3782     DWORD size;  /* max number of items in list */
3783     DWORD count; /* number of items in list */
3784     DWORD pad;
3785     DWORD_PTR unk;
3786     struct proc_thread_attr attrs[10];
3787 };
3788 
3789 static void test_ProcThreadAttributeList(void)
3790 {
3791     BOOL ret;
3792     SIZE_T size, needed;
3793     int i;
3794     struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list;
3795     HANDLE handles[4];
3796 
3797     if (!pInitializeProcThreadAttributeList)
3798     {
3799         win_skip("No support for ProcThreadAttributeList\n");
3800         return;
3801     }
3802 
3803     for (i = 0; i <= 10; i++)
3804     {
3805         needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[i]);
3806         ret = pInitializeProcThreadAttributeList(NULL, i, 0, &size);
3807         ok(!ret, "got %d\n", ret);
3808         if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */
3809             break;
3810         ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
3811         ok(size == needed, "%d: got %ld expect %ld\n", i, size, needed);
3812 
3813         memset(&list, 0xcc, sizeof(list));
3814         ret = pInitializeProcThreadAttributeList(&list, i, 0, &size);
3815         ok(ret, "got %d\n", ret);
3816         ok(list.mask == 0, "%d: got %08x\n", i, list.mask);
3817         ok(list.size == i, "%d: got %08x\n", i, list.size);
3818         ok(list.count == 0, "%d: got %08x\n", i, list.count);
3819         ok(list.unk == 0, "%d: got %08lx\n", i, list.unk);
3820     }
3821 
3822     memset(handles, 0, sizeof(handles));
3823     memset(&expect_list, 0xcc, sizeof(expect_list));
3824     expect_list.mask = 0;
3825     expect_list.size = i - 1;
3826     expect_list.count = 0;
3827     expect_list.unk = 0;
3828 
3829     ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3830     ok(!ret, "got %d\n", ret);
3831     ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %d\n", GetLastError());
3832 
3833     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL);
3834     ok(!ret, "got %d\n", ret);
3835     ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3836 
3837     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL);
3838     ok(!ret, "got %d\n", ret);
3839     ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3840 
3841     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3842     ok(ret, "got %d\n", ret);
3843 
3844     expect_list.mask |= 1 << ProcThreadAttributeParentProcess;
3845     expect_list.attrs[0].attr = PROC_THREAD_ATTRIBUTE_PARENT_PROCESS;
3846     expect_list.attrs[0].size = sizeof(handles[0]);
3847     expect_list.attrs[0].value = handles;
3848     expect_list.count++;
3849 
3850     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3851     ok(!ret, "got %d\n", ret);
3852     ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3853 
3854     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL);
3855     ok(!ret, "got %d\n", ret);
3856     ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3857 
3858     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3859     ok(ret, "got %d\n", ret);
3860 
3861     expect_list.mask |= 1 << ProcThreadAttributeHandleList;
3862     expect_list.attrs[1].attr = PROC_THREAD_ATTRIBUTE_HANDLE_LIST;
3863     expect_list.attrs[1].size = sizeof(handles);
3864     expect_list.attrs[1].value = handles;
3865     expect_list.count++;
3866 
3867     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3868     ok(!ret, "got %d\n", ret);
3869     ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3870 
3871     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3872     ok(ret || GetLastError() == ERROR_NOT_SUPPORTED, "got %d gle %d\n", ret, GetLastError());
3873 
3874     if (ret)
3875     {
3876         expect_list.mask |= 1 << ProcThreadAttributeIdealProcessor;
3877         expect_list.attrs[2].attr = PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR;
3878         expect_list.attrs[2].size = sizeof(PROCESSOR_NUMBER);
3879         expect_list.attrs[2].value = handles;
3880         expect_list.count++;
3881     }
3882 
3883     ok(!memcmp(&list, &expect_list, size), "mismatch\n");
3884 
3885     pDeleteProcThreadAttributeList(&list);
3886 }
3887 
3888 static void test_GetActiveProcessorCount(void)
3889 {
3890     DWORD count;
3891 
3892     if (!pGetActiveProcessorCount)
3893     {
3894         win_skip("GetActiveProcessorCount not available, skipping test\n");
3895         return;
3896     }
3897 
3898     count = pGetActiveProcessorCount(0);
3899     ok(count, "GetActiveProcessorCount failed, error %u\n", GetLastError());
3900 
3901     /* Test would fail on systems with more than 6400 processors */
3902     SetLastError(0xdeadbeef);
3903     count = pGetActiveProcessorCount(101);
3904     ok(count == 0, "Expeced GetActiveProcessorCount to fail\n");
3905     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3906 }
3907 
3908 START_TEST(process)
3909 {
3910     HANDLE job;
3911     BOOL b = init();
3912     ok(b, "Basic init of CreateProcess test\n");
3913     if (!b) return;
3914 
3915     if (myARGC >= 3)
3916     {
3917         if (!strcmp(myARGV[2], "dump") && myARGC >= 4)
3918         {
3919             doChild(myARGV[3], (myARGC >= 5) ? myARGV[4] : NULL);
3920             return;
3921         }
3922         else if (!strcmp(myARGV[2], "wait"))
3923         {
3924             Sleep(30000);
3925             ok(0, "Child process not killed\n");
3926             return;
3927         }
3928         else if (!strcmp(myARGV[2], "exit"))
3929         {
3930             Sleep(100);
3931             return;
3932         }
3933         else if (!strcmp(myARGV[2], "nested") && myARGC >= 4)
3934         {
3935             char                buffer[MAX_PATH];
3936             STARTUPINFOA        startup;
3937             PROCESS_INFORMATION info;
3938 
3939             memset(&startup, 0, sizeof(startup));
3940             startup.cb = sizeof(startup);
3941             startup.dwFlags = STARTF_USESHOWWINDOW;
3942             startup.wShowWindow = SW_SHOWNORMAL;
3943 
3944             sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, myARGV[3]);
3945             ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n");
3946             CloseHandle(info.hProcess);
3947             CloseHandle(info.hThread);
3948             return;
3949         }
3950 
3951         ok(0, "Unexpected command %s\n", myARGV[2]);
3952         return;
3953     }
3954 
3955     test_process_info();
3956     test_TerminateProcess();
3957     test_Startup();
3958     test_CommandLine();
3959     test_Directory();
3960     test_Toolhelp();
3961     test_Environment();
3962     test_SuspendFlag();
3963     test_DebuggingFlag();
3964     test_Console();
3965     test_ExitCode();
3966     test_OpenProcess();
3967     test_GetProcessVersion();
3968     test_GetProcessImageFileNameA();
3969     test_QueryFullProcessImageNameA();
3970     test_QueryFullProcessImageNameW();
3971     test_Handles();
3972     test_IsWow64Process();
3973     test_SystemInfo();
3974     test_RegistryQuota();
3975     test_DuplicateHandle();
3976     test_StartupNoConsole();
3977     test_DetachConsoleHandles();
3978     test_DetachStdHandles();
3979     test_GetNumaProcessorNode();
3980     test_session_info();
3981     test_GetLogicalProcessorInformationEx();
3982     test_GetActiveProcessorCount();
3983     test_largepages();
3984     test_ProcThreadAttributeList();
3985     test_SuspendProcessState();
3986     test_SuspendProcessNewThread();
3987 
3988     /* things that can be tested:
3989      *  lookup:         check the way program to be executed is searched
3990      *  handles:        check the handle inheritance stuff (+sec options)
3991      *  console:        check if console creation parameters work
3992      */
3993 
3994     if (!pCreateJobObjectW)
3995     {
3996         win_skip("No job object support\n");
3997         return;
3998     }
3999 
4000     test_IsProcessInJob();
4001     test_TerminateJobObject();
4002     test_QueryInformationJobObject();
4003     test_CompletionPort();
4004     test_KillOnJobClose();
4005     test_WaitForJobObject();
4006     job = test_AddSelfToJob();
4007     test_jobInheritance(job);
4008     test_BreakawayOk(job);
4009     CloseHandle(job);
4010 }
4011