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