Reactos
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#include "wine/heap.h"
40#ifdef __REACTOS__
41#include "winehacks.h"
42#endif
43
44/* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
45#define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
46/* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
47#define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
48
49#define expect_eq_d(expected, actual) \
50 do { \
51 int value = (actual); \
52 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
53 (int)(expected), value); \
54 } while (0)
55#define expect_eq_s(expected, actual) \
56 do { \
57 LPCSTR value = (actual); \
58 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
59 expected, value); \
60 } while (0)
61#define expect_eq_ws_i(expected, actual) \
62 do { \
63 LPCWSTR value = (actual); \
64 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
65 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
66 } while (0)
67
68static HINSTANCE hkernel32, hntdll;
69static void (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO);
70static BOOL (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD);
71static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
72static BOOL (WINAPI *pIsWow64Process2)(HANDLE, USHORT *, USHORT *);
73static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize);
74static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize);
75static DWORD (WINAPI *pK32GetProcessImageFileNameA)(HANDLE,LPSTR,DWORD);
76static HANDLE (WINAPI *pCreateJobObjectW)(LPSECURITY_ATTRIBUTES sa, LPCWSTR name);
77static HANDLE (WINAPI *pOpenJobObjectA)(DWORD access, BOOL inherit, LPCSTR name);
78static BOOL (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process);
79static BOOL (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result);
80static BOOL (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code);
81static BOOL (WINAPI *pQueryInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len, LPDWORD ret_len);
82static BOOL (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len);
83static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads);
84static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR);
85static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
86static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG);
87static NTSTATUS (WINAPI *pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS, void*, ULONG, void*, ULONG, ULONG*);
88static DWORD (WINAPI *pWTSGetActiveConsoleSessionId)(void);
89static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
90static BOOL (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*);
91static BOOL (WINAPI *pProcess32Next)(HANDLE, PROCESSENTRY32*);
92static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*);
93static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*);
94static BOOL (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
95static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
96static BOOL (WINAPI *pGetSystemCpuSetInformation)(SYSTEM_CPU_SET_INFORMATION*,ULONG,ULONG*,HANDLE,ULONG);
97static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
98static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
99static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
100static DWORD (WINAPI *pGetActiveProcessorCount)(WORD);
101static DWORD (WINAPI *pGetMaximumProcessorCount)(WORD);
102static BOOL (WINAPI *pGetProcessInformation)(HANDLE,PROCESS_INFORMATION_CLASS,void*,DWORD);
103
104/* ############################### */
105static char base[MAX_PATH];
106static char selfname[MAX_PATH];
107static char* exename;
108static char resfile[MAX_PATH];
109
110static int myARGC;
111static char** myARGV;
112
113/* As some environment variables get very long on Unix, we only test for
114 * the first 127 bytes.
115 * Note that increasing this value past 256 may exceed the buffer size
116 * limitations of the *Profile functions (at least on Wine).
117 */
118#define MAX_LISTED_ENV_VAR 128
119
120/* ---------------- portable memory allocation thingie */
121
122static char memory[1024*256];
123static char* memory_index = memory;
124
125static char* grab_memory(size_t len)
126{
127 char* ret = memory_index;
128 /* align on dword */
129 len = (len + 3) & ~3;
130 memory_index += len;
131 assert(memory_index <= memory + sizeof(memory));
132 return ret;
133}
134
135static void release_memory(void)
136{
137 memory_index = memory;
138}
139
140/* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
141
142static const char* encodeA(const char* str)
143{
144 char* ptr;
145 size_t len,i;
146
147 if (!str) return "";
148 len = strlen(str) + 1;
149 ptr = grab_memory(len * 2 + 1);
150 for (i = 0; i < len; i++)
151 sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
152 ptr[2 * len] = '\0';
153 return ptr;
154}
155
156static const char* encodeW(const WCHAR* str)
157{
158 char* ptr;
159 size_t len,i;
160
161 if (!str) return "";
162 len = lstrlenW(str) + 1;
163 ptr = grab_memory(len * 4 + 1);
164 assert(ptr);
165 for (i = 0; i < len; i++)
166 sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
167 ptr[4 * len] = '\0';
168 return ptr;
169}
170
171static unsigned decode_char(char c)
172{
173 if (c >= '0' && c <= '9') return c - '0';
174 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
175 assert(c >= 'A' && c <= 'F');
176 return c - 'A' + 10;
177}
178
179static char* decodeA(const char* str)
180{
181 char* ptr;
182 size_t len,i;
183
184 len = strlen(str) / 2;
185 if (!len--) return NULL;
186 ptr = grab_memory(len + 1);
187 for (i = 0; i < len; i++)
188 ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
189 ptr[len] = '\0';
190 return ptr;
191}
192
193/* This will be needed to decode Unicode strings saved by the child process
194 * when we test Unicode functions.
195 */
196static WCHAR* decodeW(const char* str)
197{
198 size_t len;
199 WCHAR* ptr;
200 int i;
201
202 len = strlen(str) / 4;
203 if (!len--) return NULL;
204 ptr = (WCHAR*)grab_memory(len * 2 + 1);
205 for (i = 0; i < len; i++)
206 ptr[i] = (decode_char(str[4 * i]) << 12) |
207 (decode_char(str[4 * i + 1]) << 8) |
208 (decode_char(str[4 * i + 2]) << 4) |
209 (decode_char(str[4 * i + 3]) << 0);
210 ptr[len] = '\0';
211 return ptr;
212}
213
214static void wait_and_close_child_process(PROCESS_INFORMATION *pi)
215{
216 wait_child_process(pi->hProcess);
217 CloseHandle(pi->hThread);
218 CloseHandle(pi->hProcess);
219}
220
221static void reload_child_info(const char* resfile)
222{
223 /* This forces the profile functions to reload the resource file
224 * after the child process has modified it.
225 */
226 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
227}
228
229/******************************************************************
230 * init
231 *
232 * generates basic information like:
233 * base: absolute path to curr dir
234 * selfname: the way to reinvoke ourselves
235 * exename: executable without the path
236 * function-pointers, which are not implemented in all windows versions
237 */
238static BOOL init(void)
239{
240 char *p;
241
242 myARGC = winetest_get_mainargs( &myARGV );
243 if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
244 GetModuleFileNameA( 0, selfname, sizeof(selfname) );
245
246 /* Strip the path of selfname */
247 if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1;
248 else exename = selfname;
249
250 if ((p = strrchr(exename, '/')) != NULL) exename = p + 1;
251
252 hkernel32 = GetModuleHandleA("kernel32");
253 hntdll = GetModuleHandleA("ntdll.dll");
254
255 pNtQueryInformationProcess = (void *)GetProcAddress(hntdll, "NtQueryInformationProcess");
256 pNtQueryInformationThread = (void *)GetProcAddress(hntdll, "NtQueryInformationThread");
257 pNtQuerySystemInformationEx = (void *)GetProcAddress(hntdll, "NtQuerySystemInformationEx");
258
259 pGetNativeSystemInfo = (void *) GetProcAddress(hkernel32, "GetNativeSystemInfo");
260 pGetSystemRegistryQuota = (void *) GetProcAddress(hkernel32, "GetSystemRegistryQuota");
261 pIsWow64Process = (void *) GetProcAddress(hkernel32, "IsWow64Process");
262 pIsWow64Process2 = (void *) GetProcAddress(hkernel32, "IsWow64Process2");
263 pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA");
264 pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW");
265 pK32GetProcessImageFileNameA = (void *) GetProcAddress(hkernel32, "K32GetProcessImageFileNameA");
266 pCreateJobObjectW = (void *)GetProcAddress(hkernel32, "CreateJobObjectW");
267 pOpenJobObjectA = (void *)GetProcAddress(hkernel32, "OpenJobObjectA");
268 pAssignProcessToJobObject = (void *)GetProcAddress(hkernel32, "AssignProcessToJobObject");
269 pIsProcessInJob = (void *)GetProcAddress(hkernel32, "IsProcessInJob");
270 pTerminateJobObject = (void *)GetProcAddress(hkernel32, "TerminateJobObject");
271 pQueryInformationJobObject = (void *)GetProcAddress(hkernel32, "QueryInformationJobObject");
272 pSetInformationJobObject = (void *)GetProcAddress(hkernel32, "SetInformationJobObject");
273 pCreateIoCompletionPort = (void *)GetProcAddress(hkernel32, "CreateIoCompletionPort");
274 pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode");
275 pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId");
276 pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
277 pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First");
278 pProcess32Next = (void *)GetProcAddress(hkernel32, "Process32Next");
279 pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First");
280 pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next");
281 pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
282 pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum");
283 pGetSystemCpuSetInformation = (void *)GetProcAddress(hkernel32, "GetSystemCpuSetInformation");
284 pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
285 pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
286 pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
287 pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount");
288 pGetMaximumProcessorCount = (void *)GetProcAddress(hkernel32, "GetMaximumProcessorCount");
289 pGetProcessInformation = (void *)GetProcAddress(hkernel32, "GetProcessInformation");
290
291 return TRUE;
292}
293
294/******************************************************************
295 * get_file_name
296 *
297 * generates an absolute file_name for temporary file
298 *
299 */
300static void get_file_name(char* buf)
301{
302 char path[MAX_PATH];
303
304 buf[0] = '\0';
305 GetTempPathA(sizeof(path), path);
306 GetTempFileNameA(path, "wt", 0, buf);
307}
308
309/******************************************************************
310 * static void childPrintf
311 *
312 */
313static void WINAPIV __WINE_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...)
314{
315 va_list valist;
316 char buffer[1024+4*MAX_LISTED_ENV_VAR];
317 DWORD w;
318
319 va_start(valist, fmt);
320 vsprintf(buffer, fmt, valist);
321 va_end(valist);
322 WriteFile(h, buffer, strlen(buffer), &w, NULL);
323}
324
325/* bits 0..1 contains FILE_TYPE_{UNKNOWN, CHAR, PIPE, DISK} */
326#if defined(__REACTOS__) && defined(_WIN64)
327/* This appears to be what HATTR_NULL resolves to on Windows x64 for native (not WoW) processes.
328 * It may be:
329 * HATTR_NULL (x86) | HATTR_INVALID | 0x01 */
330#define HATTR_NULL 0x0d /* NULL handle value */
331#else
332#define HATTR_NULL 0x08 /* NULL handle value */
333#endif
334#define HATTR_INVALID 0x04 /* INVALID_HANDLE_VALUE */
335#define HATTR_TYPE 0x0c /* valid handle, with type set */
336#define HATTR_UNTOUCHED 0x10 /* Identify fields untouched by GetStartupInfoW */
337#define HATTR_INHERIT 0x20 /* inheritance flag set */
338#define HATTR_PROTECT 0x40 /* protect from close flag set */
339#define HATTR_DANGLING 0x80 /* a pseudo value to show that the handle value has been copied but not inherited */
340
341#define HANDLE_UNTOUCHEDW (HANDLE)(DWORD_PTR)(0x5050505050505050ull)
342
343static unsigned encode_handle_attributes(HANDLE h)
344{
345 DWORD dw;
346 unsigned result;
347
348 if (h == NULL)
349 result = HATTR_NULL;
350 else if (h == INVALID_HANDLE_VALUE)
351 result = HATTR_INVALID;
352 else if (h == HANDLE_UNTOUCHEDW)
353 result = HATTR_UNTOUCHED;
354 else
355 {
356 result = HATTR_TYPE;
357 dw = GetFileType(h);
358 if (dw == FILE_TYPE_CHAR || dw == FILE_TYPE_DISK || dw == FILE_TYPE_PIPE)
359 {
360 DWORD info;
361 if (GetHandleInformation(h, &info))
362 {
363 if (info & HANDLE_FLAG_INHERIT)
364 result |= HATTR_INHERIT;
365 if (info & HANDLE_FLAG_PROTECT_FROM_CLOSE)
366 result |= HATTR_PROTECT;
367 }
368 }
369 else
370 dw = FILE_TYPE_UNKNOWN;
371 result |= dw;
372 }
373 return result;
374}
375
376/******************************************************************
377 * doChild
378 *
379 * output most of the information in the child process
380 */
381static void doChild(const char* file, const char* option)
382{
383 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
384 STARTUPINFOA siA;
385 STARTUPINFOW siW;
386 int i;
387 char *ptrA, *ptrA_save;
388 WCHAR *ptrW, *ptrW_save;
389 char bufA[MAX_PATH];
390 WCHAR bufW[MAX_PATH];
391 HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
392 HANDLE snapshot;
393 PROCESSENTRY32 pe;
394 BOOL ret;
395
396 if (hFile == INVALID_HANDLE_VALUE) return;
397
398 /* output of startup info (Ansi) */
399 memset(&siA, 0xA0, sizeof(siA));
400 GetStartupInfoA(&siA);
401 childPrintf(hFile,
402 "[StartupInfoA]\ncb=%08lu\nlpDesktop=%s\nlpTitle=%s\n"
403 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
404 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
405 "dwFlags=%lu\nwShowWindow=%u\n"
406 "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n"
407 "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n",
408 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
409 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize,
410 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute,
411 siA.dwFlags, siA.wShowWindow,
412 (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError,
413 encode_handle_attributes(siA.hStdInput), encode_handle_attributes(siA.hStdOutput),
414 encode_handle_attributes(siA.hStdError));
415
416 /* check the console handles in the TEB */
417 childPrintf(hFile,
418 "[TEB]\nhStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n"
419 "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n",
420 (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput,
421 (DWORD_PTR)params->hStdError,
422 encode_handle_attributes(params->hStdInput), encode_handle_attributes(params->hStdOutput),
423 encode_handle_attributes(params->hStdError));
424
425 memset(&siW, 0x50, sizeof(siW));
426 GetStartupInfoW(&siW);
427 childPrintf(hFile,
428 "[StartupInfoW]\ncb=%08lu\nlpDesktop=%s\nlpTitle=%s\n"
429 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
430 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
431 "dwFlags=%lu\nwShowWindow=%u\n"
432 "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n"
433 "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n",
434 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
435 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize,
436 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute,
437 siW.dwFlags, siW.wShowWindow,
438 (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError,
439 encode_handle_attributes(siW.hStdInput), encode_handle_attributes(siW.hStdOutput),
440 encode_handle_attributes(siW.hStdError));
441
442 /* Arguments */
443 childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
444 for (i = 0; i < myARGC; i++)
445 {
446 childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
447 }
448 childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
449 childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
450
451 /* output toolhelp information */
452 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
453 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %lu\n", GetLastError());
454 memset(&pe, 0, sizeof(pe));
455 pe.dwSize = sizeof(pe);
456 if (pProcess32First(snapshot, &pe))
457 {
458 while (pe.th32ProcessID != GetCurrentProcessId())
459 if (!pProcess32Next(snapshot, &pe)) break;
460 }
461 CloseHandle(snapshot);
462#if !defined(__REACTOS__) || !defined(_WIN64) // This doesn't work on x86_64, all Windows versions.
463 ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n");
464#endif
465 childPrintf(hFile,
466 "[Toolhelp]\ncntUsage=%lu\nth32DefaultHeapID=%Iu\n"
467 "th32ModuleID=%lu\ncntThreads=%lu\nth32ParentProcessID=%lu\n"
468 "pcPriClassBase=%lu\ndwFlags=%lu\nszExeFile=%s\n\n",
469 pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID,
470 pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase,
471 pe.dwFlags, encodeA(pe.szExeFile));
472
473 /* output of environment (Ansi) */
474 ptrA_save = ptrA = GetEnvironmentStringsA();
475 if (ptrA)
476 {
477 char env_var[MAX_LISTED_ENV_VAR];
478
479 childPrintf(hFile, "[EnvironmentA]\n");
480 i = 0;
481 while (*ptrA)
482 {
483 lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR);
484 childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
485 i++;
486 ptrA += strlen(ptrA) + 1;
487 }
488 childPrintf(hFile, "len=%d\n\n", i);
489 FreeEnvironmentStringsA(ptrA_save);
490 }
491
492 /* output of environment (Unicode) */
493 ptrW_save = ptrW = GetEnvironmentStringsW();
494 if (ptrW)
495 {
496 WCHAR env_var[MAX_LISTED_ENV_VAR];
497
498 childPrintf(hFile, "[EnvironmentW]\n");
499 i = 0;
500 while (*ptrW)
501 {
502 lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1);
503 env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
504 childPrintf(hFile, "env%d=%s\n", i, encodeW(env_var));
505 i++;
506 ptrW += lstrlenW(ptrW) + 1;
507 }
508 childPrintf(hFile, "len=%d\n\n", i);
509 FreeEnvironmentStringsW(ptrW_save);
510 }
511
512 childPrintf(hFile, "[Misc]\n");
513 if (GetCurrentDirectoryA(sizeof(bufA), bufA))
514 childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
515 if (GetCurrentDirectoryW(ARRAY_SIZE(bufW), bufW))
516 childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
517 childPrintf(hFile, "\n");
518
519 if (option && strcmp(option, "console") == 0)
520 {
521 CONSOLE_SCREEN_BUFFER_INFO sbi;
522 HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE);
523 HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
524 DWORD modeIn, modeOut;
525
526 childPrintf(hFile, "[Console]\n");
527 if (GetConsoleScreenBufferInfo(hConOut, &sbi))
528 {
529 childPrintf(hFile, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
530 sbi.dwSize.X, sbi.dwSize.Y, sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y, sbi.wAttributes);
531 childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
532 sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom);
533 childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n",
534 sbi.dwMaximumWindowSize.X, sbi.dwMaximumWindowSize.Y);
535 }
536 childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
537 GetConsoleCP(), GetConsoleOutputCP());
538 if (GetConsoleMode(hConIn, &modeIn))
539 childPrintf(hFile, "InputMode=%lu\n", modeIn);
540 if (GetConsoleMode(hConOut, &modeOut))
541 childPrintf(hFile, "OutputMode=%lu\n", modeOut);
542
543 /* now that we have written all relevant information, let's change it */
544 SetLastError(0xdeadbeef);
545 ret = SetConsoleCP(1252);
546 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
547 {
548 win_skip("Setting the codepage is not implemented\n");
549 }
550 else
551 {
552 ok(ret, "Setting CP\n");
553 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
554 }
555
556 ret = SetConsoleMode(hConIn, modeIn ^ 1);
557 ok( ret, "Setting mode (%ld)\n", GetLastError());
558 ret = SetConsoleMode(hConOut, modeOut ^ 1);
559 ok( ret, "Setting mode (%ld)\n", GetLastError());
560 sbi.dwCursorPosition.X = !sbi.dwCursorPosition.X;
561 sbi.dwCursorPosition.Y = !sbi.dwCursorPosition.Y;
562 ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition);
563 ok( ret, "Setting cursor position (%ld)\n", GetLastError());
564 }
565 if (option && strcmp(option, "stdhandle") == 0)
566 {
567 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
568 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
569
570 if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE)
571 {
572 char buf[1024];
573 DWORD r, w;
574
575 ok(ReadFile(hStdIn, buf, sizeof(buf), &r, NULL) && r > 0, "Reading message from input pipe\n");
576 childPrintf(hFile, "[StdHandle]\nmsg=%s\n\n", encodeA(buf));
577 ok(WriteFile(hStdOut, buf, r, &w, NULL) && w == r, "Writing message to output pipe\n");
578 }
579 }
580
581 if (option && strcmp(option, "exit_code") == 0)
582 {
583 childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123);
584 CloseHandle(hFile);
585 ExitProcess(123);
586 }
587
588 CloseHandle(hFile);
589}
590
591static char* getChildString(const char* sect, const char* key)
592{
593 char buf[1024+4*MAX_LISTED_ENV_VAR];
594 char* ret;
595
596 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
597 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
598 assert(!(strlen(buf) & 1));
599 ret = decodeA(buf);
600 return ret;
601}
602
603static WCHAR* getChildStringW(const char* sect, const char* key)
604{
605 char buf[1024+4*MAX_LISTED_ENV_VAR];
606 WCHAR* ret;
607
608 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
609 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
610 assert(!(strlen(buf) & 1));
611 ret = decodeW(buf);
612 return ret;
613}
614
615static int strCmp(const char* s1, const char* s2, BOOL sensitive)
616{
617 if (!s1 && !s2) return 0;
618 if (!s2) return -1;
619 if (!s1) return 1;
620 return (sensitive) ? strcmp(s1, s2) : strcasecmp(s1, s2);
621}
622
623static void ok_child_string( int line, const char *sect, const char *key,
624 const char *expect, int sensitive )
625{
626 char* result = getChildString( sect, key );
627 ok_(__FILE__, line)( strCmp(result, expect, sensitive) == 0, "%s:%s expected '%s', got '%s'\n",
628 sect, key, expect ? expect : "(null)", result );
629}
630
631static void ok_child_stringWA( int line, const char *sect, const char *key,
632 const char *expect, int sensitive )
633{
634 WCHAR* expectW;
635 CHAR* resultA;
636 DWORD len;
637 WCHAR* result = getChildStringW( sect, key );
638
639 len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0);
640 expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
641 MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len);
642
643 len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL);
644 resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR));
645 WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL);
646
647 if (sensitive)
648 ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
649 sect, key, expect ? expect : "(null)", resultA );
650 else
651 ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
652 sect, key, expect ? expect : "(null)", resultA );
653 HeapFree(GetProcessHeap(),0,expectW);
654 HeapFree(GetProcessHeap(),0,resultA);
655}
656
657static void ok_child_int( int line, const char *sect, const char *key, UINT expect )
658{
659 UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile );
660 ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result );
661}
662
663static void ok_child_hexint( int line, const char *sect, const char *key, UINT expect, UINT is_broken )
664{
665 UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile );
666 ok_(__FILE__, line)( result == expect || broken( is_broken && result == is_broken ), "%s:%s expected %#x, but got %#x\n", sect, key, expect, result );
667}
668
669#define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
670#define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
671#define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
672#define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
673#define okChildHexInt(sect, key, expect, is_broken) ok_child_hexint(__LINE__, (sect), (key), (expect), (is_broken))
674
675static void test_Startup(void)
676{
677 char buffer[2 * MAX_PATH + 25];
678 PROCESS_INFORMATION info;
679 STARTUPINFOA startup,si;
680 char *result;
681 static CHAR title[] = "I'm the title string",
682 desktop[] = "winsta0\\default",
683 empty[] = "";
684
685 /* let's start simplistic */
686 memset(&startup, 0, sizeof(startup));
687 startup.cb = sizeof(startup);
688 startup.dwFlags = STARTF_USESHOWWINDOW;
689 startup.wShowWindow = SW_SHOWNORMAL;
690
691 get_file_name(resfile);
692 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
693 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
694 wait_and_close_child_process(&info);
695
696 reload_child_info(resfile);
697 GetStartupInfoA(&si);
698 okChildInt("StartupInfoA", "cb", startup.cb);
699 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
700 okChildInt("StartupInfoA", "dwX", startup.dwX);
701 okChildInt("StartupInfoA", "dwY", startup.dwY);
702 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
703 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
704 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
705 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
706 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
707 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
708 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
709 release_memory();
710 DeleteFileA(resfile);
711
712 /* not so simplistic now */
713 memset(&startup, 0, sizeof(startup));
714 startup.cb = sizeof(startup);
715 startup.dwFlags = STARTF_USESHOWWINDOW;
716 startup.wShowWindow = SW_SHOWNORMAL;
717 startup.lpTitle = title;
718 startup.lpDesktop = desktop;
719 startup.dwXCountChars = 0x12121212;
720 startup.dwYCountChars = 0x23232323;
721 startup.dwX = 0x34343434;
722 startup.dwY = 0x45454545;
723 startup.dwXSize = 0x56565656;
724 startup.dwYSize = 0x67676767;
725 startup.dwFillAttribute = 0xA55A;
726
727 get_file_name(resfile);
728 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
729 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
730 wait_and_close_child_process(&info);
731
732 reload_child_info(resfile);
733 okChildInt("StartupInfoA", "cb", startup.cb);
734 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
735 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
736 okChildInt("StartupInfoA", "dwX", startup.dwX);
737 okChildInt("StartupInfoA", "dwY", startup.dwY);
738 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
739 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
740 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
741 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
742 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
743 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
744 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
745 release_memory();
746 DeleteFileA(resfile);
747
748 /* not so simplistic now */
749 memset(&startup, 0, sizeof(startup));
750 startup.cb = sizeof(startup);
751 startup.dwFlags = STARTF_USESHOWWINDOW;
752 startup.wShowWindow = SW_SHOWNORMAL;
753 startup.lpTitle = title;
754 startup.lpDesktop = NULL;
755 startup.dwXCountChars = 0x12121212;
756 startup.dwYCountChars = 0x23232323;
757 startup.dwX = 0x34343434;
758 startup.dwY = 0x45454545;
759 startup.dwXSize = 0x56565656;
760 startup.dwYSize = 0x67676767;
761 startup.dwFillAttribute = 0xA55A;
762
763 get_file_name(resfile);
764 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
765 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
766 wait_and_close_child_process(&info);
767
768 reload_child_info(resfile);
769 okChildInt("StartupInfoA", "cb", startup.cb);
770 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
771 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
772 okChildInt("StartupInfoA", "dwX", startup.dwX);
773 okChildInt("StartupInfoA", "dwY", startup.dwY);
774 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
775 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
776 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
777 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
778 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
779 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
780 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
781 release_memory();
782 DeleteFileA(resfile);
783
784 /* not so simplistic now */
785 memset(&startup, 0, sizeof(startup));
786 startup.cb = sizeof(startup);
787 startup.dwFlags = STARTF_USESHOWWINDOW;
788 startup.wShowWindow = SW_SHOWNORMAL;
789 startup.lpTitle = title;
790 startup.lpDesktop = empty;
791 startup.dwXCountChars = 0x12121212;
792 startup.dwYCountChars = 0x23232323;
793 startup.dwX = 0x34343434;
794 startup.dwY = 0x45454545;
795 startup.dwXSize = 0x56565656;
796 startup.dwYSize = 0x67676767;
797 startup.dwFillAttribute = 0xA55A;
798
799 get_file_name(resfile);
800 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
801 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
802 wait_and_close_child_process(&info);
803
804 reload_child_info(resfile);
805 okChildInt("StartupInfoA", "cb", startup.cb);
806 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
807 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
808 okChildInt("StartupInfoA", "dwX", startup.dwX);
809 okChildInt("StartupInfoA", "dwY", startup.dwY);
810 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
811 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
812 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
813 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
814 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
815 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
816 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
817 release_memory();
818 DeleteFileA(resfile);
819
820 /* not so simplistic now */
821 memset(&startup, 0, sizeof(startup));
822 startup.cb = sizeof(startup);
823 startup.dwFlags = STARTF_USESHOWWINDOW;
824 startup.wShowWindow = SW_SHOWNORMAL;
825 startup.lpTitle = NULL;
826 startup.lpDesktop = desktop;
827 startup.dwXCountChars = 0x12121212;
828 startup.dwYCountChars = 0x23232323;
829 startup.dwX = 0x34343434;
830 startup.dwY = 0x45454545;
831 startup.dwXSize = 0x56565656;
832 startup.dwYSize = 0x67676767;
833 startup.dwFillAttribute = 0xA55A;
834
835 get_file_name(resfile);
836 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
837 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
838 wait_and_close_child_process(&info);
839
840 reload_child_info(resfile);
841 okChildInt("StartupInfoA", "cb", startup.cb);
842 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
843 result = getChildString( "StartupInfoA", "lpTitle" );
844 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
845 "expected '%s' or null, got '%s'\n", selfname, result );
846 okChildInt("StartupInfoA", "dwX", startup.dwX);
847 okChildInt("StartupInfoA", "dwY", startup.dwY);
848 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
849 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
850 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
851 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
852 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
853 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
854 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
855 release_memory();
856 DeleteFileA(resfile);
857
858 /* not so simplistic now */
859 memset(&startup, 0, sizeof(startup));
860 startup.cb = sizeof(startup);
861 startup.dwFlags = STARTF_USESHOWWINDOW;
862 startup.wShowWindow = SW_SHOWNORMAL;
863 startup.lpTitle = empty;
864 startup.lpDesktop = desktop;
865 startup.dwXCountChars = 0x12121212;
866 startup.dwYCountChars = 0x23232323;
867 startup.dwX = 0x34343434;
868 startup.dwY = 0x45454545;
869 startup.dwXSize = 0x56565656;
870 startup.dwYSize = 0x67676767;
871 startup.dwFillAttribute = 0xA55A;
872
873 get_file_name(resfile);
874 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
875 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
876 wait_and_close_child_process(&info);
877
878 reload_child_info(resfile);
879 okChildInt("StartupInfoA", "cb", startup.cb);
880 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
881 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
882 okChildInt("StartupInfoA", "dwX", startup.dwX);
883 okChildInt("StartupInfoA", "dwY", startup.dwY);
884 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
885 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
886 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
887 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
888 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
889 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
890 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
891 release_memory();
892 DeleteFileA(resfile);
893
894 /* not so simplistic now */
895 memset(&startup, 0, sizeof(startup));
896 startup.cb = sizeof(startup);
897 startup.dwFlags = STARTF_USESHOWWINDOW;
898 startup.wShowWindow = SW_SHOWNORMAL;
899 startup.lpTitle = empty;
900 startup.lpDesktop = empty;
901 startup.dwXCountChars = 0x12121212;
902 startup.dwYCountChars = 0x23232323;
903 startup.dwX = 0x34343434;
904 startup.dwY = 0x45454545;
905 startup.dwXSize = 0x56565656;
906 startup.dwYSize = 0x67676767;
907 startup.dwFillAttribute = 0xA55A;
908
909 get_file_name(resfile);
910 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
911 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
912 wait_and_close_child_process(&info);
913
914 reload_child_info(resfile);
915 okChildInt("StartupInfoA", "cb", startup.cb);
916 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
917 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
918 okChildInt("StartupInfoA", "dwX", startup.dwX);
919 okChildInt("StartupInfoA", "dwY", startup.dwY);
920 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
921 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
922 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
923 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
924 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
925 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
926 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
927 release_memory();
928 DeleteFileA(resfile);
929
930 /* TODO: test for A/W and W/A and W/W */
931}
932
933static void test_CommandLine(void)
934{
935 char buffer[2 * MAX_PATH + 65], fullpath[MAX_PATH], *lpFilePart, *p;
936 char buffer2[MAX_PATH + 44];
937 PROCESS_INFORMATION info;
938 STARTUPINFOA startup;
939 BOOL ret;
940 LPWSTR cmdline, cmdline_backup;
941
942 memset(&startup, 0, sizeof(startup));
943 startup.cb = sizeof(startup);
944 startup.dwFlags = STARTF_USESHOWWINDOW;
945 startup.wShowWindow = SW_SHOWNORMAL;
946
947 /* failure case */
948 strcpy(buffer, "\"t:\\NotADir\\NotAFile.exe\"");
949 memset(&info, 0xa, sizeof(info));
950 ok(!CreateProcessA(buffer, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess unexpectedly succeeded\n");
951 /* Check that the effective STARTUPINFOA parameters are not modified */
952 ok(startup.cb == sizeof(startup), "unexpected cb %ld\n", startup.cb);
953 ok(startup.lpDesktop == NULL, "lpDesktop is not NULL\n");
954 ok(startup.lpTitle == NULL, "lpTitle is not NULL\n");
955 ok(startup.dwFlags == STARTF_USESHOWWINDOW, "unexpected dwFlags %04lx\n", startup.dwFlags);
956 ok(startup.wShowWindow == SW_SHOWNORMAL, "unexpected wShowWindow %d\n", startup.wShowWindow);
957 ok(!info.hProcess, "unexpected hProcess %p\n", info.hProcess);
958 ok(!info.hThread, "unexpected hThread %p\n", info.hThread);
959 ok(!info.dwProcessId, "unexpected dwProcessId %04lx\n", info.dwProcessId);
960 ok(!info.dwThreadId, "unexpected dwThreadId %04lx\n", info.dwThreadId);
961
962 /* the basics; not getting confused by the leading and trailing " */
963 get_file_name(resfile);
964 sprintf(buffer, "\"%s\" process dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
965 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
966 /* Check that the effective STARTUPINFOA parameters are not modified */
967 ok(startup.cb == sizeof(startup), "unexpected cb %ld\n", startup.cb);
968 ok(startup.lpDesktop == NULL, "lpDesktop is not NULL\n");
969 ok(startup.lpTitle == NULL, "lpTitle is not NULL\n");
970 ok(startup.dwFlags == STARTF_USESHOWWINDOW, "unexpected dwFlags %04lx\n", startup.dwFlags);
971 ok(startup.wShowWindow == SW_SHOWNORMAL, "unexpected wShowWindow %d\n", startup.wShowWindow);
972 wait_and_close_child_process(&info);
973
974 reload_child_info(resfile);
975 okChildInt("Arguments", "argcA", 5);
976 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
977 okChildString("Arguments", "argvA5", NULL);
978 okChildString("Arguments", "CommandLineA", buffer);
979 release_memory();
980 DeleteFileA(resfile);
981
982 /* test main()'s quotes handling */
983 get_file_name(resfile);
984 sprintf(buffer, "\"%s\" process dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
985 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
986 wait_and_close_child_process(&info);
987
988 reload_child_info(resfile);
989 okChildInt("Arguments", "argcA", 7);
990 okChildString("Arguments", "argvA4", "a\"b\\");
991 okChildString("Arguments", "argvA5", "c\"");
992 okChildString("Arguments", "argvA6", "d");
993 okChildString("Arguments", "argvA7", NULL);
994 okChildString("Arguments", "CommandLineA", buffer);
995 release_memory();
996 DeleteFileA(resfile);
997
998 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
999 assert ( lpFilePart != 0);
1000 *(lpFilePart -1 ) = 0;
1001 SetCurrentDirectoryA( fullpath );
1002
1003 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]
1004 * and " escaping.
1005 */
1006 get_file_name(resfile);
1007 /* Use exename to avoid buffer containing things like 'C:' */
1008 sprintf(buffer, "./%s process dump \"%s\" \"\"\"\"", exename, resfile);
1009 SetLastError(0xdeadbeef);
1010 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1011 ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError());
1012 wait_and_close_child_process(&info);
1013
1014 reload_child_info(resfile);
1015 sprintf(buffer, "./%s", exename);
1016 okChildInt("Arguments", "argcA", 5);
1017 okChildString("Arguments", "argvA0", buffer);
1018 okChildString("Arguments", "argvA4", "\"");
1019 okChildString("Arguments", "argvA5", NULL);
1020 release_memory();
1021 DeleteFileA(resfile);
1022
1023 get_file_name(resfile);
1024 /* Use exename to avoid buffer containing things like 'C:' */
1025 sprintf(buffer, ".\\%s process dump \"%s\"", exename, resfile);
1026 SetLastError(0xdeadbeef);
1027 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1028 ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError());
1029 wait_and_close_child_process(&info);
1030
1031 reload_child_info(resfile);
1032 sprintf(buffer, ".\\%s", exename);
1033 okChildString("Arguments", "argvA0", buffer);
1034 release_memory();
1035 DeleteFileA(resfile);
1036
1037 get_file_name(resfile);
1038 p = strrchr(fullpath, '\\');
1039 /* Use exename to avoid buffer containing things like 'C:' */
1040 if (p) sprintf(buffer, "..%s/%s process dump \"%s\"", p, exename, resfile);
1041 else sprintf(buffer, "./%s process dump \"%s\"", exename, resfile);
1042 SetLastError(0xdeadbeef);
1043 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1044 ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError());
1045 wait_and_close_child_process(&info);
1046
1047 reload_child_info(resfile);
1048 if (p) sprintf(buffer, "..%s/%s", p, exename);
1049 else sprintf(buffer, "./%s", exename);
1050 okChildString("Arguments", "argvA0", buffer);
1051 release_memory();
1052 DeleteFileA(resfile);
1053
1054 /* Using AppName */
1055 get_file_name(resfile);
1056 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
1057 assert ( lpFilePart != 0);
1058 *(lpFilePart -1 ) = 0;
1059 p = strrchr(fullpath, '\\');
1060 /* Use exename to avoid buffer containing things like 'C:' */
1061 if (p) sprintf(buffer, "..%s/%s", p, exename);
1062 else sprintf(buffer, "./%s", exename);
1063 sprintf(buffer2, "dummy process dump \"%s\"", resfile);
1064 SetLastError(0xdeadbeef);
1065 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1066 ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError());
1067 wait_and_close_child_process(&info);
1068
1069 reload_child_info(resfile);
1070 okChildString("Arguments", "argvA0", "dummy");
1071 okChildString("Arguments", "CommandLineA", buffer2);
1072 okChildStringWA("Arguments", "CommandLineW", buffer2);
1073 release_memory();
1074 DeleteFileA(resfile);
1075 SetCurrentDirectoryA( base );
1076
1077 if (0) /* Test crashes on NT-based Windows. */
1078 {
1079 /* Test NULL application name and command line parameters. */
1080 SetLastError(0xdeadbeef);
1081 ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1082 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1083 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1084 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
1085 }
1086
1087 buffer[0] = '\0';
1088
1089 /* Test empty application name parameter. */
1090 SetLastError(0xdeadbeef);
1091 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1092 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1093 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1094 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1095 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1096 "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError());
1097
1098 buffer2[0] = '\0';
1099
1100 /* Test empty application name and command line parameters. */
1101 SetLastError(0xdeadbeef);
1102 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1103 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1104 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1105 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1106 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1107 "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError());
1108
1109 /* Test empty command line parameter. */
1110 SetLastError(0xdeadbeef);
1111 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1112 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1113 ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
1114 GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ ||
1115 GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ ||
1116 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */,
1117 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1118
1119 strcpy(buffer, "doesnotexist.exe");
1120 strcpy(buffer2, "does not exist.exe");
1121
1122 /* Test nonexistent application name. */
1123 SetLastError(0xdeadbeef);
1124 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1125 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1126 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1127
1128 SetLastError(0xdeadbeef);
1129 ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1130 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1131 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1132
1133 /* Test nonexistent command line parameter. */
1134 SetLastError(0xdeadbeef);
1135 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1136 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1137 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1138
1139 SetLastError(0xdeadbeef);
1140 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1141 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1142 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1143
1144 /* Test whether GetCommandLineW reads directly from TEB or from a cached address */
1145 cmdline = GetCommandLineW();
1146 ok(cmdline == NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer, "Expected address from TEB, got %p\n", cmdline);
1147
1148 cmdline_backup = cmdline;
1149 NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer = NULL;
1150 cmdline = GetCommandLineW();
1151 ok(cmdline == cmdline_backup, "Expected cached address from TEB, got %p\n", cmdline);
1152 NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer = cmdline_backup;
1153}
1154
1155static void test_Directory(void)
1156{
1157 char buffer[2 * MAX_PATH + 25];
1158 PROCESS_INFORMATION info;
1159 STARTUPINFOA startup;
1160 char windir[MAX_PATH];
1161 static CHAR cmdline[] = "winver.exe";
1162
1163 memset(&startup, 0, sizeof(startup));
1164 startup.cb = sizeof(startup);
1165 startup.dwFlags = STARTF_USESHOWWINDOW;
1166 startup.wShowWindow = SW_SHOWNORMAL;
1167
1168 /* the basics */
1169 get_file_name(resfile);
1170 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1171 GetWindowsDirectoryA( windir, sizeof(windir) );
1172 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n");
1173 wait_and_close_child_process(&info);
1174
1175 reload_child_info(resfile);
1176 okChildIString("Misc", "CurrDirA", windir);
1177 release_memory();
1178 DeleteFileA(resfile);
1179
1180 /* search PATH for the exe if directory is NULL */
1181 ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1182 ok(TerminateProcess(info.hProcess, 0), "Child process termination\n");
1183 CloseHandle(info.hThread);
1184 CloseHandle(info.hProcess);
1185
1186 /* if any directory is provided, don't search PATH, error on bad directory */
1187 SetLastError(0xdeadbeef);
1188 memset(&info, 0, sizeof(info));
1189 ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L,
1190 NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n");
1191 ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %ld\n", GetLastError());
1192 ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n");
1193}
1194
1195static void test_Toolhelp(void)
1196{
1197#if defined(__REACTOS__) && defined(_WIN64)
1198 skip("test_Toolhelp() times out on x86_64.\n");
1199#else
1200 char buffer[2 * MAX_PATH + 27];
1201 STARTUPINFOA startup;
1202 PROCESS_INFORMATION info;
1203 HANDLE process, thread, snapshot;
1204 DWORD nested_pid;
1205 PROCESSENTRY32 pe;
1206 THREADENTRY32 te;
1207 DWORD ret;
1208 int i;
1209
1210 memset(&startup, 0, sizeof(startup));
1211 startup.cb = sizeof(startup);
1212 startup.dwFlags = STARTF_USESHOWWINDOW;
1213 startup.wShowWindow = SW_SHOWNORMAL;
1214
1215 get_file_name(resfile);
1216 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1217 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1218 wait_and_close_child_process(&info);
1219
1220 reload_child_info(resfile);
1221 okChildInt("Toolhelp", "cntUsage", 0);
1222 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1223 okChildInt("Toolhelp", "th32ModuleID", 0);
1224 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1225 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1226 okChildInt("Toolhelp", "dwFlags", 0);
1227
1228 release_memory();
1229 DeleteFileA(resfile);
1230
1231 get_file_name(resfile);
1232 sprintf(buffer, "\"%s\" process nested \"%s\"", selfname, resfile);
1233 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1234 wait_child_process(info.hProcess);
1235
1236 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1237 ok(process != NULL, "OpenProcess failed %lu\n", GetLastError());
1238 CloseHandle(process);
1239
1240 CloseHandle(info.hProcess);
1241 CloseHandle(info.hThread);
1242
1243 for (i = 0; i < 20; i++)
1244 {
1245 SetLastError(0xdeadbeef);
1246 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1247 ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %lu\n", GetLastError());
1248 if (!process) break;
1249 CloseHandle(process);
1250 Sleep(100);
1251 }
1252 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1253 ok(i < 20 || broken(i == 20), "process object not released\n");
1254
1255 /* Look for the nested process by pid */
1256 reload_child_info(resfile);
1257 nested_pid = GetPrivateProfileIntA("Nested", "Pid", 0, resfile);
1258 DeleteFileA(resfile);
1259
1260 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1261 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %lu\n", GetLastError());
1262 memset(&pe, 0, sizeof(pe));
1263 pe.dwSize = sizeof(pe);
1264 if (pProcess32First(snapshot, &pe))
1265 {
1266 while (pe.th32ProcessID != nested_pid)
1267 if (!pProcess32Next(snapshot, &pe)) break;
1268 }
1269 CloseHandle(snapshot);
1270 ok(pe.th32ProcessID == nested_pid, "failed to find nested child process\n");
1271 ok(pe.th32ParentProcessID == info.dwProcessId, "nested child process has parent %lu instead of %lu\n", pe.th32ParentProcessID, info.dwProcessId);
1272 ok(stricmp(pe.szExeFile, exename) == 0, "nested executable is %s instead of %s\n", pe.szExeFile, exename);
1273
1274 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID);
1275 ok(process != NULL, "OpenProcess failed %lu\n", GetLastError());
1276
1277 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1278 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %lu\n", GetLastError());
1279 memset(&te, 0, sizeof(te));
1280 te.dwSize = sizeof(te);
1281 if (pThread32First(snapshot, &te))
1282 {
1283 while (te.th32OwnerProcessID != pe.th32ProcessID)
1284 if (!pThread32Next(snapshot, &te)) break;
1285 }
1286 CloseHandle(snapshot);
1287 ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1288
1289 thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID);
1290 ok(thread != NULL, "OpenThread failed %lu\n", GetLastError());
1291 ret = ResumeThread(thread);
1292 ok(ret == 1, "expected 1, got %lu\n", ret);
1293 CloseHandle(thread);
1294
1295 wait_child_process(process);
1296 CloseHandle(process);
1297
1298 reload_child_info(resfile);
1299 okChildInt("Toolhelp", "cntUsage", 0);
1300 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1301 okChildInt("Toolhelp", "th32ModuleID", 0);
1302 okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1303 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1304 okChildInt("Toolhelp", "dwFlags", 0);
1305
1306 release_memory();
1307 DeleteFileA(resfile);
1308#endif
1309}
1310
1311static BOOL is_str_env_drive_dir(const char* str)
1312{
1313 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1314 str[3] == '=' && str[4] == str[1];
1315}
1316
1317/* compared expected child's environment (in gesA) from actual
1318 * environment our child got
1319 */
1320static void cmpEnvironment(const char* gesA)
1321{
1322 int i, clen;
1323 const char* ptrA;
1324 char* res;
1325 char key[32];
1326 BOOL found;
1327
1328 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1329
1330 /* now look each parent env in child */
1331 if ((ptrA = gesA) != NULL)
1332 {
1333 while (*ptrA)
1334 {
1335 for (i = 0; i < clen; i++)
1336 {
1337 sprintf(key, "env%d", i);
1338 res = getChildString("EnvironmentA", key);
1339 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1340 break;
1341 }
1342 found = i < clen;
1343 ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1344
1345 ptrA += strlen(ptrA) + 1;
1346 release_memory();
1347 }
1348 }
1349 /* and each child env in parent */
1350 for (i = 0; i < clen; i++)
1351 {
1352 sprintf(key, "env%d", i);
1353 res = getChildString("EnvironmentA", key);
1354 if ((ptrA = gesA) != NULL)
1355 {
1356 while (*ptrA)
1357 {
1358 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1359 break;
1360 ptrA += strlen(ptrA) + 1;
1361 }
1362 if (!*ptrA) ptrA = NULL;
1363 }
1364
1365 if (!is_str_env_drive_dir(res))
1366 {
1367 found = ptrA != NULL;
1368 ok(found, "Child-env string %s isn't in parent process\n", res);
1369 }
1370 /* else => should also test we get the right per drive default directory here... */
1371 }
1372}
1373
1374static void test_Environment(void)
1375{
1376 char buffer[2 * MAX_PATH + 25];
1377 PROCESS_INFORMATION info;
1378 STARTUPINFOA startup;
1379 char *child_env;
1380 int child_env_len;
1381 char *ptr;
1382 char *ptr2;
1383 char *env;
1384 int slen;
1385
1386 memset(&startup, 0, sizeof(startup));
1387 startup.cb = sizeof(startup);
1388 startup.dwFlags = STARTF_USESHOWWINDOW;
1389 startup.wShowWindow = SW_SHOWNORMAL;
1390
1391 /* the basics */
1392 get_file_name(resfile);
1393 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1394 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1395 wait_and_close_child_process(&info);
1396
1397 reload_child_info(resfile);
1398 env = GetEnvironmentStringsA();
1399 cmpEnvironment(env);
1400 release_memory();
1401 DeleteFileA(resfile);
1402
1403 memset(&startup, 0, sizeof(startup));
1404 startup.cb = sizeof(startup);
1405 startup.dwFlags = STARTF_USESHOWWINDOW;
1406 startup.wShowWindow = SW_SHOWNORMAL;
1407
1408 /* the basics */
1409 get_file_name(resfile);
1410 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1411
1412 child_env_len = 0;
1413 ptr = env;
1414 while(*ptr)
1415 {
1416 slen = strlen(ptr)+1;
1417 child_env_len += slen;
1418 ptr += slen;
1419 }
1420 /* Add space for additional environment variables */
1421 child_env_len += 256;
1422 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1423
1424 ptr = child_env;
1425 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1426 ptr += strlen(ptr) + 1;
1427 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1428 ptr += strlen(ptr) + 1;
1429 strcpy(ptr, "FOO=BAR");
1430 ptr += strlen(ptr) + 1;
1431 strcpy(ptr, "BAR=FOOBAR");
1432 ptr += strlen(ptr) + 1;
1433 /* copy all existing variables except:
1434 * - PATH (already set above)
1435 * - the directory definitions (=[A-Z]:=)
1436 */
1437 for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1438 {
1439 if (strncmp(ptr2, "PATH=", 5) != 0 &&
1440 !is_str_env_drive_dir(ptr2))
1441 {
1442 strcpy(ptr, ptr2);
1443 ptr += strlen(ptr) + 1;
1444 }
1445 }
1446 *ptr = '\0';
1447 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1448 wait_and_close_child_process(&info);
1449
1450 reload_child_info(resfile);
1451 cmpEnvironment(child_env);
1452
1453 HeapFree(GetProcessHeap(), 0, child_env);
1454 FreeEnvironmentStringsA(env);
1455 release_memory();
1456 DeleteFileA(resfile);
1457}
1458
1459static void test_SuspendFlag(void)
1460{
1461 char buffer[2 * MAX_PATH + 25];
1462 PROCESS_INFORMATION info;
1463 STARTUPINFOA startup, us;
1464 DWORD exit_status;
1465 char *result;
1466
1467 /* let's start simplistic */
1468 memset(&startup, 0, sizeof(startup));
1469 startup.cb = sizeof(startup);
1470 startup.dwFlags = STARTF_USESHOWWINDOW;
1471 startup.wShowWindow = SW_SHOWNORMAL;
1472
1473 get_file_name(resfile);
1474 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1475 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1476
1477 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1478 Sleep(100);
1479 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1480 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1481
1482 wait_and_close_child_process(&info);
1483
1484 GetStartupInfoA(&us);
1485
1486 reload_child_info(resfile);
1487 okChildInt("StartupInfoA", "cb", startup.cb);
1488 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1489 result = getChildString( "StartupInfoA", "lpTitle" );
1490 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1491 "expected '%s' or null, got '%s'\n", selfname, result );
1492 okChildInt("StartupInfoA", "dwX", startup.dwX);
1493 okChildInt("StartupInfoA", "dwY", startup.dwY);
1494 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1495 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1496 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1497 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1498 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1499 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1500 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1501 release_memory();
1502 DeleteFileA(resfile);
1503}
1504
1505static void test_DebuggingFlag(void)
1506{
1507 char buffer[2 * MAX_PATH + 25];
1508 void *processbase = NULL;
1509 PROCESS_INFORMATION info;
1510 STARTUPINFOA startup, us;
1511 DEBUG_EVENT de;
1512 unsigned dbg = 0;
1513 char *result;
1514
1515 /* let's start simplistic */
1516 memset(&startup, 0, sizeof(startup));
1517 startup.cb = sizeof(startup);
1518 startup.dwFlags = STARTF_USESHOWWINDOW;
1519 startup.wShowWindow = SW_SHOWNORMAL;
1520
1521 get_file_name(resfile);
1522 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1523 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1524
1525 /* get all startup events up to the entry point break exception */
1526 do
1527 {
1528 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1529 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1530 if (!dbg)
1531 {
1532 ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1533 "first event: %ld\n", de.dwDebugEventCode);
1534 processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1535 }
1536 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1537 ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT ||
1538 de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1539 } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1540
1541 ok(dbg, "I have seen a debug event\n");
1542 wait_and_close_child_process(&info);
1543
1544 GetStartupInfoA(&us);
1545
1546 reload_child_info(resfile);
1547 okChildInt("StartupInfoA", "cb", startup.cb);
1548 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1549 result = getChildString( "StartupInfoA", "lpTitle" );
1550 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1551 "expected '%s' or null, got '%s'\n", selfname, result );
1552 okChildInt("StartupInfoA", "dwX", startup.dwX);
1553 okChildInt("StartupInfoA", "dwY", startup.dwY);
1554 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1555 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1556 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1557 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1558 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1559 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1560 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1561 release_memory();
1562 DeleteFileA(resfile);
1563}
1564
1565static void test_Console(void)
1566{
1567 char buffer[2 * MAX_PATH + 35];
1568 PROCESS_INFORMATION info;
1569 STARTUPINFOA startup, us;
1570 SECURITY_ATTRIBUTES sa;
1571 CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC;
1572 DWORD modeIn, modeOut, modeInC, modeOutC;
1573 DWORD cpIn, cpOut, cpInC, cpOutC;
1574 DWORD w;
1575 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1576 const char* msg = "This is a std-handle inheritance test.";
1577 unsigned msg_len;
1578 BOOL run_tests = TRUE;
1579 char *result;
1580
1581 memset(&startup, 0, sizeof(startup));
1582 startup.cb = sizeof(startup);
1583 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1584 startup.wShowWindow = SW_SHOWNORMAL;
1585
1586 sa.nLength = sizeof(sa);
1587 sa.lpSecurityDescriptor = NULL;
1588 sa.bInheritHandle = TRUE;
1589
1590 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1591 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1592
1593 /* first, we need to be sure we're attached to a console */
1594 if (startup.hStdInput == INVALID_HANDLE_VALUE || startup.hStdOutput == INVALID_HANDLE_VALUE)
1595 {
1596 /* this fails either when this test process is run detached from console
1597 * (unlikely, as this very process must be explicitly created with detached flag),
1598 * or is attached to a Wine's shell-no-window kind of console (if the later, detach from it)
1599 */
1600 FreeConsole();
1601 /* we're not attached to a console, let's do it */
1602 AllocConsole();
1603 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1604 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1605 }
1606 /* now verify everything's ok */
1607 ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1608 ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1609 startup.hStdError = startup.hStdOutput;
1610
1611 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1612 ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1613 ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1614 cpIn = GetConsoleCP();
1615 cpOut = GetConsoleOutputCP();
1616
1617 get_file_name(resfile);
1618 sprintf(buffer, "\"%s\" process dump \"%s\" console", selfname, resfile);
1619 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1620 wait_and_close_child_process(&info);
1621
1622 reload_child_info(resfile);
1623 /* now get the modification the child has made, and resets parents expected values */
1624 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1625 ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1626 ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1627
1628 SetConsoleMode(startup.hStdInput, modeIn);
1629 SetConsoleMode(startup.hStdOutput, modeOut);
1630
1631 /* don't test flag that is changed at startup if WINETEST_COLOR is set */
1632 modeOut = (modeOut & ~ENABLE_VIRTUAL_TERMINAL_PROCESSING) |
1633 (modeOutC & ENABLE_VIRTUAL_TERMINAL_PROCESSING);
1634
1635 cpInC = GetConsoleCP();
1636 cpOutC = GetConsoleOutputCP();
1637
1638 /* Try to set invalid CP */
1639 SetLastError(0xdeadbeef);
1640 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1641 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1642 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1643 "GetLastError: expecting %u got %lu\n",
1644 ERROR_INVALID_PARAMETER, GetLastError());
1645 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1646 run_tests = FALSE;
1647
1648
1649 SetLastError(0xdeadbeef);
1650 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1651 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1652 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1653 "GetLastError: expecting %u got %lu\n",
1654 ERROR_INVALID_PARAMETER, GetLastError());
1655
1656 SetConsoleCP(cpIn);
1657 SetConsoleOutputCP(cpOut);
1658
1659 GetStartupInfoA(&us);
1660
1661 okChildInt("StartupInfoA", "cb", startup.cb);
1662 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1663 result = getChildString( "StartupInfoA", "lpTitle" );
1664 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1665 "expected '%s' or null, got '%s'\n", selfname, result );
1666 okChildInt("StartupInfoA", "dwX", startup.dwX);
1667 okChildInt("StartupInfoA", "dwY", startup.dwY);
1668 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1669 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1670 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1671 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1672 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1673 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1674 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1675
1676 /* check child correctly inherited the console */
1677 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1678 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1679 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1680 okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1681 okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1682 okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1683 okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1684 okChildInt("Console", "Attributes", sbi.wAttributes);
1685 okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1686 okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1687 okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1688 okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1689 okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1690 okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1691 okChildInt("Console", "InputCP", cpIn);
1692 okChildInt("Console", "OutputCP", cpOut);
1693 okChildInt("Console", "InputMode", modeIn);
1694 okChildInt("Console", "OutputMode", modeOut);
1695
1696 if (run_tests)
1697 {
1698 ok(cpInC == 1252, "Wrong console CP (expected 1252 got %ld/%ld)\n", cpInC, cpIn);
1699 ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %ld/%ld)\n", cpOutC, cpOut);
1700 }
1701 else
1702 win_skip("Setting the codepage is not implemented\n");
1703
1704 ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1705 ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1706
1707 release_memory();
1708 DeleteFileA(resfile);
1709
1710 ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1711 ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(),
1712 &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1713 "Duplicating as inheritable child-output pipe\n");
1714 CloseHandle(hChildOut);
1715
1716 ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1717 ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(),
1718 &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1719 "Duplicating as inheritable child-input pipe\n");
1720 CloseHandle(hChildIn);
1721
1722 memset(&startup, 0, sizeof(startup));
1723 startup.cb = sizeof(startup);
1724 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1725 startup.wShowWindow = SW_SHOWNORMAL;
1726 startup.hStdInput = hChildInInh;
1727 startup.hStdOutput = hChildOutInh;
1728 startup.hStdError = hChildOutInh;
1729
1730 get_file_name(resfile);
1731 sprintf(buffer, "\"%s\" process dump \"%s\" stdhandle", selfname, resfile);
1732 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1733 ok(CloseHandle(hChildInInh), "Closing handle\n");
1734 ok(CloseHandle(hChildOutInh), "Closing handle\n");
1735
1736 msg_len = strlen(msg) + 1;
1737 ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1738 ok(w == msg_len, "Should have written %u bytes, actually wrote %lu\n", msg_len, w);
1739 memset(buffer, 0, sizeof(buffer));
1740 ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1741 ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1742
1743 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1744 ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1745
1746 wait_and_close_child_process(&info);
1747
1748 reload_child_info(resfile);
1749 okChildString("StdHandle", "msg", msg);
1750
1751 release_memory();
1752 DeleteFileA(resfile);
1753}
1754
1755static void test_ExitCode(void)
1756{
1757 char buffer[2 * MAX_PATH + 35];
1758 PROCESS_INFORMATION info;
1759 STARTUPINFOA startup;
1760 DWORD code;
1761
1762 /* let's start simplistic */
1763 memset(&startup, 0, sizeof(startup));
1764 startup.cb = sizeof(startup);
1765 startup.dwFlags = STARTF_USESHOWWINDOW;
1766 startup.wShowWindow = SW_SHOWNORMAL;
1767
1768 get_file_name(resfile);
1769 sprintf(buffer, "\"%s\" process dump \"%s\" exit_code", selfname, resfile);
1770 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1771
1772 /* not wait_child_process() because of the exit code */
1773 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1774
1775 reload_child_info(resfile);
1776 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1777 okChildInt("ExitCode", "value", code);
1778
1779 release_memory();
1780 DeleteFileA(resfile);
1781}
1782
1783static void test_OpenProcess(void)
1784{
1785 HANDLE hproc;
1786 void *addr1;
1787 MEMORY_BASIC_INFORMATION info;
1788 SIZE_T dummy, read_bytes;
1789 BOOL ret;
1790
1791 /* without PROCESS_VM_OPERATION */
1792 hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1793 ok(hproc != NULL, "OpenProcess error %ld\n", GetLastError());
1794
1795 SetLastError(0xdeadbeef);
1796 addr1 = VirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1797 ok(!addr1, "VirtualAllocEx should fail\n");
1798 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1799 { /* Win9x */
1800 CloseHandle(hproc);
1801 win_skip("VirtualAllocEx not implemented\n");
1802 return;
1803 }
1804 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1805
1806 read_bytes = 0xdeadbeef;
1807 SetLastError(0xdeadbeef);
1808 ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes);
1809 ok(ret, "ReadProcessMemory error %ld\n", GetLastError());
1810 ok(read_bytes == sizeof(dummy), "wrong read bytes %Id\n", read_bytes);
1811
1812 CloseHandle(hproc);
1813
1814 hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1815 ok(hproc != NULL, "OpenProcess error %ld\n", GetLastError());
1816
1817 addr1 = VirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1818 ok(addr1 != NULL, "VirtualAllocEx error %ld\n", GetLastError());
1819
1820 /* without PROCESS_QUERY_INFORMATION */
1821 SetLastError(0xdeadbeef);
1822 ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1823 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1824 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1825
1826 /* without PROCESS_VM_READ */
1827 read_bytes = 0xdeadbeef;
1828 SetLastError(0xdeadbeef);
1829 ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1830 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1831 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1832 ok(read_bytes == 0, "wrong read bytes %Id\n", read_bytes);
1833
1834 CloseHandle(hproc);
1835
1836 hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1837
1838 memset(&info, 0xcc, sizeof(info));
1839 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1840 ok(read_bytes == sizeof(info), "VirtualQueryEx error %ld\n", GetLastError());
1841
1842 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1843 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1844 ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect);
1845 ok(info.RegionSize == 0x10000, "%Ix != 0x10000\n", info.RegionSize);
1846 ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State);
1847 /* NT reports Protect == 0 for a not committed memory block */
1848 ok(info.Protect == 0 /* NT */ ||
1849 info.Protect == PAGE_NOACCESS, /* Win9x */
1850 "%lx != PAGE_NOACCESS\n", info.Protect);
1851 ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
1852
1853 SetLastError(0xdeadbeef);
1854 ok(!VirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1855 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1856 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1857
1858 CloseHandle(hproc);
1859
1860 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1861 if (hproc)
1862 {
1863 SetLastError(0xdeadbeef);
1864 memset(&info, 0xcc, sizeof(info));
1865 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1866 if (read_bytes) /* win8 */
1867 {
1868 ok(read_bytes == sizeof(info), "VirtualQueryEx error %ld\n", GetLastError());
1869 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1870 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1871 ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect);
1872 ok(info.RegionSize == 0x10000, "%Ix != 0x10000\n", info.RegionSize);
1873 ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State);
1874 ok(info.Protect == 0, "%lx != PAGE_NOACCESS\n", info.Protect);
1875 ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
1876 }
1877 else /* before win8 */
1878 ok(broken(GetLastError() == ERROR_ACCESS_DENIED), "wrong error %ld\n", GetLastError());
1879
1880 SetLastError(0xdeadbeef);
1881 ok(!VirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1882 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1883 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1884
1885 CloseHandle(hproc);
1886 }
1887
1888 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1889}
1890
1891static void test_GetProcessVersion(void)
1892{
1893 static char cmdline[] = "winver.exe";
1894 PROCESS_INFORMATION pi;
1895 STARTUPINFOA si;
1896 DWORD ret;
1897
1898 SetLastError(0xdeadbeef);
1899 ret = GetProcessVersion(0);
1900 ok(ret, "GetProcessVersion error %lu\n", GetLastError());
1901
1902 SetLastError(0xdeadbeef);
1903 ret = GetProcessVersion(GetCurrentProcessId());
1904 ok(ret, "GetProcessVersion error %lu\n", GetLastError());
1905
1906 memset(&si, 0, sizeof(si));
1907 si.cb = sizeof(si);
1908 si.dwFlags = STARTF_USESHOWWINDOW;
1909 si.wShowWindow = SW_HIDE;
1910 SetLastError(0xdeadbeef);
1911 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1912 ok(ret, "CreateProcess error %lu\n", GetLastError());
1913
1914 SetLastError(0xdeadbeef);
1915 ret = GetProcessVersion(pi.dwProcessId);
1916 ok(ret, "GetProcessVersion error %lu\n", GetLastError());
1917
1918 SetLastError(0xdeadbeef);
1919 ret = TerminateProcess(pi.hProcess, 0);
1920 ok(ret, "TerminateProcess error %lu\n", GetLastError());
1921
1922 CloseHandle(pi.hProcess);
1923 CloseHandle(pi.hThread);
1924}
1925
1926static void test_GetProcessImageFileNameA(void)
1927{
1928 DWORD rc;
1929 CHAR process[MAX_PATH];
1930 static const char harddisk[] = "\\Device\\HarddiskVolume";
1931
1932 if (!pK32GetProcessImageFileNameA)
1933 {
1934 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1935 return;
1936 }
1937
1938 /* callers must guess the buffer size */
1939 SetLastError(0xdeadbeef);
1940 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1941 ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1942 "K32GetProcessImageFileNameA(no buffer): returned %lu, le=%lu\n", rc, GetLastError());
1943
1944 *process = '\0';
1945 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1946 expect_eq_d(rc, lstrlenA(process));
1947 if (strncmp(process, harddisk, lstrlenA(harddisk)))
1948 {
1949 todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1950 return;
1951 }
1952
1953 if (!pQueryFullProcessImageNameA)
1954 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1955 else
1956 {
1957 CHAR image[MAX_PATH];
1958 DWORD length;
1959
1960 length = sizeof(image);
1961 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1962 expect_eq_d(length, lstrlenA(image));
1963 ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1964 }
1965}
1966
1967static void test_QueryFullProcessImageNameA(void)
1968{
1969#define INIT_STR "Just some words"
1970 DWORD length, size;
1971 CHAR buf[MAX_PATH], module[MAX_PATH];
1972
1973 if (!pQueryFullProcessImageNameA)
1974 {
1975 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1976 return;
1977 }
1978
1979 *module = '\0';
1980 SetLastError(0); /* old Windows don't reset it on success */
1981 size = GetModuleFileNameA(NULL, module, sizeof(module));
1982 ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %lu le=%lu\n", size, GetLastError());
1983
1984 /* get the buffer length without \0 terminator */
1985 length = sizeof(buf);
1986 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1987 expect_eq_d(length, lstrlenA(buf));
1988 ok((buf[0] == '\\' && buf[1] == '\\') ||
1989 lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1990
1991 /* when the buffer is too small
1992 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1993 * - the size variable is not modified
1994 * tested with the biggest too small size
1995 */
1996 size = length;
1997 sprintf(buf,INIT_STR);
1998 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1999 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2000 expect_eq_d(length, size);
2001 expect_eq_s(INIT_STR, buf);
2002
2003 /* retest with smaller buffer size
2004 */
2005 size = 4;
2006 sprintf(buf,INIT_STR);
2007 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
2008 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2009 expect_eq_d(4, size);
2010 expect_eq_s(INIT_STR, buf);
2011
2012 /* this is a difference between the ansi and the unicode version
2013 * the unicode version crashes when the size is big enough to hold
2014 * the result while the ansi version throws an error
2015 */
2016 size = 1024;
2017 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
2018 expect_eq_d(1024, size);
2019 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
2020}
2021
2022static void test_QueryFullProcessImageNameW(void)
2023{
2024 HANDLE hSelf;
2025 WCHAR module_name[1024], device[1024];
2026 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
2027 WCHAR buf[1024];
2028 DWORD size, len;
2029 DWORD flags;
2030
2031 if (!pQueryFullProcessImageNameW)
2032 {
2033 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
2034 return;
2035 }
2036
2037 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
2038
2039 /* GetCurrentProcess pseudo-handle */
2040 size = ARRAY_SIZE(buf);
2041 expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
2042 expect_eq_d(lstrlenW(buf), size);
2043 expect_eq_ws_i(buf, module_name);
2044
2045 hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
2046 /* Real handle */
2047 size = ARRAY_SIZE(buf);
2048 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2049 expect_eq_d(lstrlenW(buf), size);
2050 expect_eq_ws_i(buf, module_name);
2051
2052 /* Buffer too small */
2053 size = lstrlenW(module_name)/2;
2054 lstrcpyW(buf, deviceW);
2055 SetLastError(0xdeadbeef);
2056 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2057 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2058 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2059 expect_eq_ws_i(deviceW, buf); /* buffer not changed */
2060
2061 /* Too small - not space for NUL terminator */
2062 size = lstrlenW(module_name);
2063 SetLastError(0xdeadbeef);
2064 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2065 expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
2066 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2067
2068 /* NULL buffer */
2069 size = 0;
2070 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
2071 expect_eq_d(0, size);
2072 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2073
2074 /* Buffer too small */
2075 size = lstrlenW(module_name)/2;
2076 SetLastError(0xdeadbeef);
2077 lstrcpyW(buf, module_name);
2078 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2079 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2080 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2081 expect_eq_ws_i(module_name, buf); /* buffer not changed */
2082
2083 /* Invalid flags - a few arbitrary values only */
2084 for (flags = 2; flags <= 15; ++flags)
2085 {
2086 size = ARRAY_SIZE(buf);
2087 SetLastError(0xdeadbeef);
2088 *(DWORD*)buf = 0x13579acf;
2089 todo_wine
2090 {
2091 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, flags, buf, &size));
2092 expect_eq_d((DWORD)ARRAY_SIZE(buf), size); /* size not changed */
2093 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
2094 expect_eq_d(0x13579acf, *(DWORD*)buf); /* buffer not changed */
2095 }
2096 }
2097 for (flags = 16; flags != 0; flags <<= 1)
2098 {
2099 size = ARRAY_SIZE(buf);
2100 SetLastError(0xdeadbeef);
2101 *(DWORD*)buf = 0x13579acf;
2102 todo_wine
2103 {
2104 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, flags, buf, &size));
2105 expect_eq_d((DWORD)ARRAY_SIZE(buf), size); /* size not changed */
2106 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
2107 expect_eq_d(0x13579acf, *(DWORD*)buf); /* buffer not changed */
2108 }
2109 }
2110
2111 /* native path */
2112 size = ARRAY_SIZE(buf);
2113 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2114 expect_eq_d(lstrlenW(buf), size);
2115 ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2116 ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2117
2118 module_name[2] = '\0';
2119 *device = '\0';
2120 size = QueryDosDeviceW(module_name, device, ARRAY_SIZE(device));
2121 ok(size, "QueryDosDeviceW failed: le=%lu\n", GetLastError());
2122 len = lstrlenW(device);
2123 ok(size >= len+2, "expected %ld to be greater than %ld+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2124
2125 if (size >= lstrlenW(buf))
2126 {
2127 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2128 }
2129 else
2130 {
2131 ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2132 buf[len] = '\0';
2133 ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2134 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));
2135 }
2136
2137 CloseHandle(hSelf);
2138}
2139
2140static void test_Handles(void)
2141{
2142 HANDLE handle = GetCurrentProcess();
2143 HANDLE h2, h3;
2144 BOOL ret;
2145 DWORD code;
2146
2147 ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2148 handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2149 "invalid current process handle %p\n", handle );
2150 ret = GetExitCodeProcess( handle, &code );
2151 ok( ret, "GetExitCodeProcess failed err %lu\n", GetLastError() );
2152#ifdef _WIN64
2153 /* truncated handle */
2154 SetLastError( 0xdeadbeef );
2155 handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2156 ret = GetExitCodeProcess( handle, &code );
2157 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2158 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() );
2159 /* sign-extended handle */
2160 SetLastError( 0xdeadbeef );
2161 handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle);
2162 ret = GetExitCodeProcess( handle, &code );
2163 ok( ret, "GetExitCodeProcess failed err %lu\n", GetLastError() );
2164 /* invalid high-word */
2165 SetLastError( 0xdeadbeef );
2166 handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2167 ret = GetExitCodeProcess( handle, &code );
2168 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2169 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() );
2170#endif
2171
2172 handle = GetStdHandle( STD_ERROR_HANDLE );
2173 ok( handle != 0, "handle %p\n", handle );
2174 DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &h3,
2175 0, TRUE, DUPLICATE_SAME_ACCESS );
2176 SetStdHandle( STD_ERROR_HANDLE, h3 );
2177 CloseHandle( (HANDLE)STD_ERROR_HANDLE );
2178 h2 = GetStdHandle( STD_ERROR_HANDLE );
2179 ok( h2 == 0 ||
2180 broken( h2 == h3) || /* nt4, w2k */
2181 broken( h2 == INVALID_HANDLE_VALUE), /* win9x */
2182 "wrong handle %p/%p\n", h2, h3 );
2183 SetStdHandle( STD_ERROR_HANDLE, handle );
2184}
2185
2186static void test_IsWow64Process(void)
2187{
2188 PROCESS_INFORMATION pi;
2189 STARTUPINFOA si;
2190 DWORD ret;
2191 BOOL is_wow64;
2192 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2193 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2194
2195 if (!pIsWow64Process)
2196 {
2197 win_skip("IsWow64Process is not available\n");
2198 return;
2199 }
2200
2201 memset(&si, 0, sizeof(si));
2202 si.cb = sizeof(si);
2203 si.dwFlags = STARTF_USESHOWWINDOW;
2204 si.wShowWindow = SW_HIDE;
2205 ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2206 if (ret)
2207 {
2208 trace("Created process %s\n", cmdline_wow64);
2209 is_wow64 = FALSE;
2210 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2211 ok(ret, "IsWow64Process failed.\n");
2212 ok(is_wow64, "is_wow64 returned FALSE.\n");
2213
2214 ret = TerminateProcess(pi.hProcess, 0);
2215 ok(ret, "TerminateProcess error\n");
2216
2217 CloseHandle(pi.hProcess);
2218 CloseHandle(pi.hThread);
2219 }
2220
2221 memset(&si, 0, sizeof(si));
2222 si.cb = sizeof(si);
2223 si.dwFlags = STARTF_USESHOWWINDOW;
2224 si.wShowWindow = SW_HIDE;
2225 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2226 if (ret)
2227 {
2228 trace("Created process %s\n", cmdline);
2229 is_wow64 = TRUE;
2230 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2231 ok(ret, "IsWow64Process failed.\n");
2232 ok(!is_wow64, "is_wow64 returned TRUE.\n");
2233
2234 ret = TerminateProcess(pi.hProcess, 0);
2235 ok(ret, "TerminateProcess error\n");
2236
2237 CloseHandle(pi.hProcess);
2238 CloseHandle(pi.hThread);
2239 }
2240}
2241
2242static void test_IsWow64Process2(void)
2243{
2244 PROCESS_INFORMATION pi;
2245 STARTUPINFOA si;
2246 BOOL ret, is_wow64;
2247 USHORT machine, native_machine;
2248 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2249 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2250#ifdef __i386__
2251 USHORT expect_native = IMAGE_FILE_MACHINE_I386;
2252#elif defined __x86_64__
2253 USHORT expect_native = IMAGE_FILE_MACHINE_AMD64;
2254#elif defined __arm__
2255 USHORT expect_native = IMAGE_FILE_MACHINE_ARMNT;
2256#elif defined __aarch64__
2257 USHORT expect_native = IMAGE_FILE_MACHINE_ARM64;
2258#else
2259 USHORT expect_native = 0;
2260#endif
2261
2262 if (!pIsWow64Process2)
2263 {
2264 win_skip("IsWow64Process2 is not available\n");
2265 return;
2266 }
2267
2268 memset(&si, 0, sizeof(si));
2269 si.cb = sizeof(si);
2270 SetLastError(0xdeadbeef);
2271 ret = CreateProcessA(cmdline_wow64, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2272 if (ret)
2273 {
2274 SetLastError(0xdeadbeef);
2275 machine = native_machine = 0xdead;
2276 ret = pIsWow64Process2(pi.hProcess, &machine, &native_machine);
2277 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2278
2279#if defined(__i386__) || defined(__x86_64__)
2280 ok(machine == IMAGE_FILE_MACHINE_I386, "got %#x\n", machine);
2281 ok( native_machine == IMAGE_FILE_MACHINE_AMD64 ||
2282 native_machine == IMAGE_FILE_MACHINE_ARM64, "got %#x\n", native_machine);
2283 expect_native = native_machine;
2284#else
2285 skip("not supported architecture\n");
2286#endif
2287 ret = TerminateProcess(pi.hProcess, 0);
2288 ok(ret, "TerminateProcess error\n");
2289
2290 CloseHandle(pi.hProcess);
2291 CloseHandle(pi.hThread);
2292 }
2293
2294 memset(&si, 0, sizeof(si));
2295 si.cb = sizeof(si);
2296 SetLastError(0xdeadbeef);
2297 ret = CreateProcessA(cmdline, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2298 ok(ret, "CreateProcess error %lu\n", GetLastError());
2299
2300 SetLastError(0xdeadbeef);
2301 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2302 ok(ret, "IsWow64Process error %lu\n", GetLastError());
2303
2304 SetLastError(0xdeadbeef);
2305 machine = native_machine = 0xdead;
2306 ret = pIsWow64Process2(pi.hProcess, &machine, &native_machine);
2307 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2308
2309 ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine);
2310 ok(native_machine == expect_native, "got %#x\n", native_machine);
2311
2312 SetLastError(0xdeadbeef);
2313 machine = 0xdead;
2314 ret = pIsWow64Process2(pi.hProcess, &machine, NULL);
2315 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2316 ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine);
2317
2318 ret = TerminateProcess(pi.hProcess, 0);
2319 ok(ret, "TerminateProcess error\n");
2320
2321 CloseHandle(pi.hProcess);
2322 CloseHandle(pi.hThread);
2323
2324 SetLastError(0xdeadbeef);
2325 ret = pIsWow64Process(GetCurrentProcess(), &is_wow64);
2326 ok(ret, "IsWow64Process error %lu\n", GetLastError());
2327
2328 SetLastError(0xdeadbeef);
2329 machine = native_machine = 0xdead;
2330 ret = pIsWow64Process2(GetCurrentProcess(), &machine, &native_machine);
2331 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2332
2333 if (is_wow64)
2334 {
2335 ok(machine == IMAGE_FILE_MACHINE_I386, "got %#x\n", machine);
2336 ok(native_machine == expect_native, "got %#x\n", native_machine);
2337 }
2338 else
2339 {
2340 ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine);
2341 ok(native_machine == expect_native, "got %#x\n", native_machine);
2342 }
2343
2344 SetLastError(0xdeadbeef);
2345 machine = 0xdead;
2346 ret = pIsWow64Process2(GetCurrentProcess(), &machine, NULL);
2347 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2348 if (is_wow64)
2349 ok(machine == IMAGE_FILE_MACHINE_I386, "got %#x\n", machine);
2350 else
2351 ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine);
2352}
2353
2354static void test_SystemInfo(void)
2355{
2356 SYSTEM_INFO si, nsi;
2357 BOOL is_wow64;
2358 USHORT machine, native_machine;
2359
2360 if (!pGetNativeSystemInfo)
2361 {
2362 win_skip("GetNativeSystemInfo is not available\n");
2363 return;
2364 }
2365
2366 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2367
2368 GetSystemInfo(&si);
2369 pGetNativeSystemInfo(&nsi);
2370 if (is_wow64)
2371 {
2372 if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2373 {
2374 ok(nsi.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2375 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2376 nsi.wProcessorArchitecture);
2377 if (pIsWow64Process2 && pIsWow64Process2(GetCurrentProcess(), &machine, &native_machine) &&
2378 native_machine == IMAGE_FILE_MACHINE_ARM64)
2379 {
2380 ok(nsi.dwProcessorType == PROCESSOR_INTEL_PENTIUM, "got %ld\n", nsi.dwProcessorType);
2381 ok(nsi.wProcessorLevel == 15, "got %d\n", nsi.wProcessorLevel);
2382 ok(nsi.wProcessorRevision == 0x40a, "got %d\n", nsi.wProcessorRevision);
2383 }
2384 else ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664, "got %ld\n", nsi.dwProcessorType);
2385 }
2386 }
2387 else
2388 {
2389 ok(si.wProcessorArchitecture == nsi.wProcessorArchitecture,
2390 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2391 si.wProcessorArchitecture, nsi.wProcessorArchitecture);
2392 ok(si.dwProcessorType == nsi.dwProcessorType,
2393 "Expected no difference for dwProcessorType, got %ld and %ld\n",
2394 si.dwProcessorType, nsi.dwProcessorType);
2395 }
2396}
2397
2398static void test_ProcessorCount(void)
2399{
2400 DWORD active, maximum;
2401
2402 if (!pGetActiveProcessorCount || !pGetMaximumProcessorCount)
2403 {
2404 win_skip("GetActiveProcessorCount or GetMaximumProcessorCount is not available\n");
2405 return;
2406 }
2407
2408 active = pGetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
2409 maximum = pGetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
2410 ok(active <= maximum,
2411 "Number of active processors %li is greater than maximum number of processors %li\n",
2412 active, maximum);
2413}
2414
2415static void test_RegistryQuota(void)
2416{
2417 BOOL ret;
2418 DWORD max_quota, used_quota;
2419
2420 if (!pGetSystemRegistryQuota)
2421 {
2422 win_skip("GetSystemRegistryQuota is not available\n");
2423 return;
2424 }
2425
2426 ret = pGetSystemRegistryQuota(NULL, NULL);
2427 ok(ret == TRUE,
2428 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2429
2430 ret = pGetSystemRegistryQuota(&max_quota, NULL);
2431 ok(ret == TRUE,
2432 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2433
2434 ret = pGetSystemRegistryQuota(NULL, &used_quota);
2435 ok(ret == TRUE,
2436 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2437
2438 ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2439 ok(ret == TRUE,
2440 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2441}
2442
2443static void test_TerminateProcess(void)
2444{
2445 static char cmdline[] = "winver.exe";
2446 PROCESS_INFORMATION pi;
2447 STARTUPINFOA si;
2448 DWORD ret;
2449 HANDLE dummy, thread;
2450
2451 memset(&si, 0, sizeof(si));
2452 si.cb = sizeof(si);
2453 SetLastError(0xdeadbeef);
2454 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2455 ok(ret, "CreateProcess error %lu\n", GetLastError());
2456
2457 SetLastError(0xdeadbeef);
2458 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2459 ok(thread != 0, "CreateRemoteThread error %ld\n", GetLastError());
2460
2461 /* create a not closed thread handle duplicate in the target process */
2462 SetLastError(0xdeadbeef);
2463 ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy,
2464 0, FALSE, DUPLICATE_SAME_ACCESS);
2465 ok(ret, "DuplicateHandle error %lu\n", GetLastError());
2466
2467 SetLastError(0xdeadbeef);
2468 ret = TerminateThread(thread, 0);
2469 ok(ret, "TerminateThread error %lu\n", GetLastError());
2470 CloseHandle(thread);
2471
2472 SetLastError(0xdeadbeef);
2473 ret = TerminateProcess(pi.hProcess, 0);
2474 ok(ret, "TerminateProcess error %lu\n", GetLastError());
2475
2476 CloseHandle(pi.hProcess);
2477 CloseHandle(pi.hThread);
2478}
2479
2480static void test_DuplicateHandle(void)
2481{
2482 char path[MAX_PATH], file_name[MAX_PATH];
2483 HANDLE f, fmin, out;
2484 DWORD info;
2485 BOOL r;
2486
2487#if defined(__REACTOS__) && defined(_WIN64)
2488 if (is_reactos()) {
2489 ok(FALSE, "FIXME: test_DuplicateHandle() deadlocks on ReactOS x64!\n");
2490 return;
2491 }
2492#endif
2493 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2494 GetCurrentProcess(), &out, 0, FALSE,
2495 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2496 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2497 r = GetHandleInformation(out, &info);
2498 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2499 ok(info == 0, "info = %lx\n", info);
2500 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2501 CloseHandle(out);
2502
2503 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2504 GetCurrentProcess(), &out, 0, TRUE,
2505 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2506 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2507 r = GetHandleInformation(out, &info);
2508 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2509 ok(info == HANDLE_FLAG_INHERIT, "info = %lx\n", info);
2510 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2511 CloseHandle(out);
2512
2513 GetTempPathA(MAX_PATH, path);
2514 GetTempFileNameA(path, "wt", 0, file_name);
2515 f = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2516 if (f == INVALID_HANDLE_VALUE)
2517 {
2518 ok(0, "could not create %s\n", file_name);
2519 return;
2520 }
2521
2522 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2523 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2524 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2525 ok(f == out, "f != out\n");
2526 r = GetHandleInformation(out, &info);
2527 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2528 ok(info == 0, "info = %lx\n", info);
2529
2530 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2531 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2532 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2533 ok(f == out, "f != out\n");
2534 r = GetHandleInformation(out, &info);
2535 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2536 ok(info == HANDLE_FLAG_INHERIT, "info = %lx\n", info);
2537
2538 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
2539 ok(r, "SetHandleInformation error %lu\n", GetLastError());
2540 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2541 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2542 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2543 ok(f != out, "f == out\n");
2544 r = GetHandleInformation(out, &info);
2545 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2546 ok(info == HANDLE_FLAG_INHERIT, "info = %lx\n", info);
2547 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2548 ok(r, "SetHandleInformation error %lu\n", GetLastError());
2549
2550 /* Test if DuplicateHandle allocates first free handle */
2551 if (f > out)
2552 {
2553 fmin = out;
2554 }
2555 else
2556 {
2557 fmin = f;
2558 f = out;
2559 }
2560 CloseHandle(fmin);
2561 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2562 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2563 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2564 ok(f == out, "f != out\n");
2565 CloseHandle(out);
2566 DeleteFileA(file_name);
2567
2568 f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2569 ok(f != INVALID_HANDLE_VALUE, "Failed to open CONIN$ %lu\n", GetLastError());
2570 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2571 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2572 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2573 ok(f == out || broken(/* Win7 */ (((ULONG_PTR)f & 3) == 3) && (f != out)), "f != out\n");
2574 CloseHandle(out);
2575
2576 /* Test DUPLICATE_SAME_ATTRIBUTES */
2577 f = CreateFileA("NUL", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
2578 ok(f != INVALID_HANDLE_VALUE, "Failed to open NUL %lu\n", GetLastError());
2579 r = GetHandleInformation(f, &info);
2580 ok(r && info == 0, "Unexpected info %lx\n", info);
2581
2582 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2583 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES);
2584 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2585 r = GetHandleInformation(out, &info);
2586 ok(r && info == 0, "Unexpected info %lx\n", info);
2587 CloseHandle(out);
2588
2589 r = SetHandleInformation(f, HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE,
2590 HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE);
2591 ok(r, "SetHandleInformation error %lu\n", GetLastError());
2592 info = 0xdeabeef;
2593 r = GetHandleInformation(f, &info);
2594 ok(r && info == (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE), "Unexpected info %lx\n", info);
2595 ok(r, "SetHandleInformation error %lu\n", GetLastError());
2596 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2597 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES);
2598 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2599 info = 0xdeabeef;
2600 r = GetHandleInformation(out, &info);
2601 ok(r && info == (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE), "Unexpected info %lx\n", info);
2602 r = SetHandleInformation(out, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2603 ok(r, "SetHandleInformation error %lu\n", GetLastError());
2604 CloseHandle(out);
2605 r = SetHandleInformation(f, HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2606 ok(r, "SetHandleInformation error %lu\n", GetLastError());
2607 CloseHandle(f);
2608
2609 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &out,
2610 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES);
2611 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2612 info = 0xdeabeef;
2613 r = GetHandleInformation(out, &info);
2614 ok(r && info == 0, "Unexpected info %lx\n", info);
2615 CloseHandle(out);
2616}
2617
2618#define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2619static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2620{
2621 LPOVERLAPPED overlapped;
2622 ULONG_PTR value;
2623 DWORD key;
2624 BOOL ret;
2625
2626 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait);
2627
2628 ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
2629 if (ret)
2630 {
2631 ok_(__FILE__, line)(key == ekey, "unexpected key %lx\n", key);
2632 ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2633 ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2634 }
2635}
2636
2637#define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2638static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2639{
2640 BOOL ret;
2641 char buffer[MAX_PATH + 19];
2642 STARTUPINFOA si = {0};
2643
2644 sprintf(buffer, "\"%s\" process %s", selfname, command);
2645
2646 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2647 ok_(__FILE__, line)(ret, "CreateProcess error %lu\n", GetLastError());
2648}
2649
2650#define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
2651static void _test_assigned_proc(int line, HANDLE job, unsigned int count, ...)
2652{
2653 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20];
2654 JOBOBJECT_BASIC_PROCESS_ID_LIST *list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2655 unsigned int i, pid;
2656 va_list valist;
2657 DWORD size;
2658 BOOL ret;
2659
2660 memset(buf, 0, sizeof(buf));
2661 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, list, sizeof(buf), &size);
2662 ok_(__FILE__, line)(ret, "failed to get process id list, error %lu\n", GetLastError());
2663
2664 ok_(__FILE__, line)(list->NumberOfAssignedProcesses == count,
2665 "expected %u assigned processes, got %lu\n", count, list->NumberOfAssignedProcesses);
2666 ok_(__FILE__, line)(list->NumberOfProcessIdsInList == count,
2667 "expected %u process IDs, got %lu\n", count, list->NumberOfProcessIdsInList);
2668
2669 va_start(valist, count);
2670 for (i = 0; i < min(count, list->NumberOfProcessIdsInList); ++i)
2671 {
2672 pid = va_arg(valist, unsigned int);
2673 ok_(__FILE__, line)(pid == list->ProcessIdList[i],
2674 "wrong pid %u: expected %#04x, got %#04Ix\n", i, pid, list->ProcessIdList[i]);
2675 }
2676 va_end(valist);
2677}
2678
2679#define test_accounting(a, b, c, d) _test_accounting(__LINE__, a, b, c, d)
2680static void _test_accounting(int line, HANDLE job, unsigned int total, unsigned int active, unsigned int terminated)
2681{
2682 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION info;
2683 DWORD size;
2684 BOOL ret;
2685
2686 memset(&info, 0, sizeof(info));
2687 ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &info, sizeof(info), &size);
2688 ok_(__FILE__, line)(ret, "failed to get accounting information, error %lu\n", GetLastError());
2689
2690 ok_(__FILE__, line)(info.TotalProcesses == total,
2691 "expected %u total processes, got %lu\n", total, info.TotalProcesses);
2692 ok_(__FILE__, line)(info.ActiveProcesses == active,
2693 "expected %u active processes, got %lu\n", active, info.ActiveProcesses);
2694 ok_(__FILE__, line)(info.TotalTerminatedProcesses == terminated,
2695 "expected %u terminated processes, got %lu\n", terminated, info.TotalTerminatedProcesses);
2696}
2697
2698static void test_IsProcessInJob(void)
2699{
2700 HANDLE job, job2;
2701 PROCESS_INFORMATION pi;
2702 BOOL ret, out;
2703
2704 if (!pIsProcessInJob)
2705 {
2706 win_skip("IsProcessInJob not available.\n");
2707 return;
2708 }
2709
2710 job = pCreateJobObjectW(NULL, NULL);
2711 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2712
2713 job2 = pCreateJobObjectW(NULL, NULL);
2714 ok(job2 != NULL, "CreateJobObject error %lu\n", GetLastError());
2715
2716 create_process("wait", &pi);
2717
2718 out = TRUE;
2719 ret = pIsProcessInJob(pi.hProcess, job, &out);
2720 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2721 ok(!out, "IsProcessInJob returned out=%u\n", out);
2722 test_assigned_proc(job, 0);
2723 test_accounting(job, 0, 0, 0);
2724
2725 out = TRUE;
2726 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2727 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2728 ok(!out, "IsProcessInJob returned out=%u\n", out);
2729 test_assigned_proc(job2, 0);
2730 test_accounting(job2, 0, 0, 0);
2731
2732 ret = pAssignProcessToJobObject(job, pi.hProcess);
2733 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2734
2735 out = FALSE;
2736 ret = pIsProcessInJob(pi.hProcess, job, &out);
2737 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2738 ok(out, "IsProcessInJob returned out=%u\n", out);
2739 test_assigned_proc(job, 1, pi.dwProcessId);
2740 test_accounting(job, 1, 1, 0);
2741
2742 out = TRUE;
2743 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2744 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2745 ok(!out, "IsProcessInJob returned out=%u\n", out);
2746 test_assigned_proc(job2, 0);
2747 test_accounting(job2, 0, 0, 0);
2748
2749 out = FALSE;
2750 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2751 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2752 ok(out, "IsProcessInJob returned out=%u\n", out);
2753
2754 TerminateProcess(pi.hProcess, 0);
2755 wait_child_process(pi.hProcess);
2756
2757 out = FALSE;
2758 ret = pIsProcessInJob(pi.hProcess, job, &out);
2759 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2760 ok(out, "IsProcessInJob returned out=%u\n", out);
2761#ifdef __REACTOS__
2762 if (GetNTVersion() >= _WIN32_WINNT_WIN8) {
2763 test_assigned_proc(job, 1);
2764 test_accounting(job, 1, 1, 0);
2765 } else {
2766#endif
2767 test_assigned_proc(job, 0);
2768 test_accounting(job, 1, 0, 0);
2769#ifdef __REACTOS__
2770 }
2771#endif
2772
2773 CloseHandle(pi.hProcess);
2774 CloseHandle(pi.hThread);
2775 CloseHandle(job);
2776 CloseHandle(job2);
2777}
2778
2779static void test_TerminateJobObject(void)
2780{
2781 HANDLE job;
2782 PROCESS_INFORMATION pi;
2783 BOOL ret;
2784 DWORD dwret;
2785
2786 job = pCreateJobObjectW(NULL, NULL);
2787 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2788 test_assigned_proc(job, 0);
2789 test_accounting(job, 0, 0, 0);
2790
2791 create_process("wait", &pi);
2792
2793 ret = pAssignProcessToJobObject(job, pi.hProcess);
2794 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2795 test_assigned_proc(job, 1, pi.dwProcessId);
2796 test_accounting(job, 1, 1, 0);
2797
2798 ret = pTerminateJobObject(job, 123);
2799 ok(ret, "TerminateJobObject error %lu\n", GetLastError());
2800
2801 /* not wait_child_process() because of the exit code */
2802 dwret = WaitForSingleObject(pi.hProcess, 1000);
2803 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret);
2804 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2805 test_assigned_proc(job, 0);
2806 test_accounting(job, 1, 0, 0);
2807
2808 ret = GetExitCodeProcess(pi.hProcess, &dwret);
2809 ok(ret, "GetExitCodeProcess error %lu\n", GetLastError());
2810 ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
2811 "wrong exitcode %lu\n", dwret);
2812
2813 CloseHandle(pi.hProcess);
2814 CloseHandle(pi.hThread);
2815
2816 /* Test adding an already terminated process to a job object */
2817 create_process("exit", &pi);
2818 wait_child_process(pi.hProcess);
2819
2820 SetLastError(0xdeadbeef);
2821 ret = pAssignProcessToJobObject(job, pi.hProcess);
2822 ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2823 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2824 test_assigned_proc(job, 0);
2825 test_accounting(job, 1, 0, 0);
2826
2827 CloseHandle(pi.hProcess);
2828 CloseHandle(pi.hThread);
2829
2830 CloseHandle(job);
2831}
2832
2833static void test_QueryInformationJobObject(void)
2834{
2835 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2836 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2837 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2838 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2839 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting_info;
2840 DWORD ret_len;
2841 PROCESS_INFORMATION pi[2];
2842 char buffer[50];
2843 HANDLE job, sem;
2844 BOOL ret;
2845
2846 job = pCreateJobObjectW(NULL, NULL);
2847 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2848
2849 /* Only active processes are returned */
2850 sprintf(buffer, "sync kernel32-process-%lx", GetCurrentProcessId());
2851 sem = CreateSemaphoreA(NULL, 0, 1, buffer + 5);
2852 ok(sem != NULL, "CreateSemaphoreA failed le=%lu\n", GetLastError());
2853 create_process(buffer, &pi[0]);
2854
2855 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2856 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2857
2858 ReleaseSemaphore(sem, 1, NULL);
2859 wait_and_close_child_process(&pi[0]);
2860
2861 create_process("wait", &pi[0]);
2862 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2863 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2864
2865 create_process("wait", &pi[1]);
2866 ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2867 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2868
2869 SetLastError(0xdeadbeef);
2870 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2871 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len);
2872 ok(!ret, "QueryInformationJobObject expected failure\n");
2873 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2874
2875 SetLastError(0xdeadbeef);
2876 memset(buf, 0, sizeof(buf));
2877 pid_list->NumberOfAssignedProcesses = 42;
2878 pid_list->NumberOfProcessIdsInList = 42;
2879 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2880 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len);
2881 ok(!ret, "QueryInformationJobObject expected failure\n");
2882 expect_eq_d(ERROR_MORE_DATA, GetLastError());
2883 if (ret)
2884 {
2885 expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2886 expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2887 }
2888
2889 memset(buf, 0, sizeof(buf));
2890 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2891 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
2892 if(ret)
2893 {
2894 if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2895 win_skip("Number of assigned processes broken on Win 8\n");
2896 else
2897 {
2898 ULONG_PTR *list = pid_list->ProcessIdList;
2899
2900 ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]),
2901 "QueryInformationJobObject returned ret_len=%lu\n", ret_len);
2902
2903 expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2904 expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2905 expect_eq_d(pi[0].dwProcessId, list[0]);
2906 expect_eq_d(pi[1].dwProcessId, list[1]);
2907 }
2908 }
2909
2910 /* test JobObjectBasicLimitInformation */
2911 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2912 sizeof(*basic_limit_info) - 1, &ret_len);
2913 ok(!ret, "QueryInformationJobObject expected failure\n");
2914 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2915
2916 ret_len = 0xdeadbeef;
2917 memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2918 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2919 sizeof(*basic_limit_info), &ret_len);
2920 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
2921 ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%lu\n", ret_len);
2922 expect_eq_d(0, basic_limit_info->LimitFlags);
2923
2924 /* test JobObjectExtendedLimitInformation */
2925 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2926 sizeof(ext_limit_info) - 1, &ret_len);
2927 ok(!ret, "QueryInformationJobObject expected failure\n");
2928 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2929
2930 ret_len = 0xdeadbeef;
2931 memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2932 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2933 sizeof(ext_limit_info), &ret_len);
2934 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
2935 ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%lu\n", ret_len);
2936 expect_eq_d(0, basic_limit_info->LimitFlags);
2937
2938 /* test JobObjectBasicAccountingInformation */
2939 ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting_info,
2940 sizeof(basic_accounting_info), &ret_len);
2941 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
2942 ok(ret_len == sizeof(basic_accounting_info), "QueryInformationJobObject returned ret_len=%lu\n", ret_len);
2943 expect_eq_d(3, basic_accounting_info.TotalProcesses);
2944#if defined(__REACTOS__)
2945 ok(basic_accounting_info.ActiveProcesses == 2 || broken(basic_accounting_info.ActiveProcesses == 3) /* Win8+ */, "Expected %d == %d\n", basic_accounting_info.ActiveProcesses, 2);
2946#else
2947 expect_eq_d(2, basic_accounting_info.ActiveProcesses);
2948#endif
2949
2950 TerminateProcess(pi[0].hProcess, 0);
2951 CloseHandle(pi[0].hProcess);
2952 CloseHandle(pi[0].hThread);
2953
2954 TerminateProcess(pi[1].hProcess, 0);
2955 CloseHandle(pi[1].hProcess);
2956 CloseHandle(pi[1].hThread);
2957
2958 CloseHandle(job);
2959}
2960
2961static void test_CompletionPort(void)
2962{
2963 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
2964 PROCESS_INFORMATION pi, pi2;
2965 HANDLE job, port;
2966 BOOL ret;
2967
2968 job = pCreateJobObjectW(NULL, NULL);
2969 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2970
2971 create_process("wait", &pi2);
2972 ret = pAssignProcessToJobObject(job, pi2.hProcess);
2973 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2974
2975 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2976 ok(port != NULL, "CreateIoCompletionPort error %lu\n", GetLastError());
2977
2978 port_info.CompletionKey = job;
2979 port_info.CompletionPort = port;
2980 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2981 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
2982
2983 create_process("wait", &pi);
2984
2985 ret = pAssignProcessToJobObject(job, pi.hProcess);
2986 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2987
2988 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi2.dwProcessId, 0);
2989 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2990
2991 TerminateProcess(pi.hProcess, 0);
2992 wait_child_process(pi.hProcess);
2993
2994 test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2995 TerminateProcess(pi2.hProcess, 0);
2996 wait_child_process(pi2.hProcess);
2997 CloseHandle(pi2.hProcess);
2998 CloseHandle(pi2.hThread);
2999
3000 test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi2.dwProcessId, 0);
3001 test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100);
3002
3003 CloseHandle(pi.hProcess);
3004 CloseHandle(pi.hThread);
3005 CloseHandle(job);
3006 CloseHandle(port);
3007}
3008
3009static void test_KillOnJobClose(void)
3010{
3011 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
3012 PROCESS_INFORMATION pi;
3013 DWORD dwret;
3014 HANDLE job;
3015 BOOL ret;
3016
3017 job = pCreateJobObjectW(NULL, NULL);
3018 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
3019
3020 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
3021 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3022 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3023 {
3024 win_skip("Kill on job close limit not available\n");
3025 return;
3026 }
3027 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
3028 test_assigned_proc(job, 0);
3029 test_accounting(job, 0, 0, 0);
3030
3031 create_process("wait", &pi);
3032
3033 ret = pAssignProcessToJobObject(job, pi.hProcess);
3034 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
3035 test_assigned_proc(job, 1, pi.dwProcessId);
3036 test_accounting(job, 1, 1, 0);
3037
3038 CloseHandle(job);
3039
3040 /* not wait_child_process() for the kill */
3041 dwret = WaitForSingleObject(pi.hProcess, 1000);
3042 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret);
3043 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
3044
3045 CloseHandle(pi.hProcess);
3046 CloseHandle(pi.hThread);
3047}
3048
3049static void test_WaitForJobObject(void)
3050{
3051 HANDLE job, sem;
3052 char buffer[50];
3053 PROCESS_INFORMATION pi;
3054 BOOL ret;
3055 DWORD dwret;
3056
3057 /* test waiting for a job object when the process is killed */
3058 job = pCreateJobObjectW(NULL, NULL);
3059 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
3060
3061 dwret = WaitForSingleObject(job, 100);
3062 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret);
3063
3064 create_process("wait", &pi);
3065
3066 ret = pAssignProcessToJobObject(job, pi.hProcess);
3067 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
3068
3069 dwret = WaitForSingleObject(job, 100);
3070 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret);
3071
3072 ret = pTerminateJobObject(job, 123);
3073 ok(ret, "TerminateJobObject error %lu\n", GetLastError());
3074
3075 dwret = WaitForSingleObject(job, 500);
3076 ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
3077 "WaitForSingleObject returned %lu\n", dwret);
3078
3079 if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
3080 {
3081 CloseHandle(pi.hProcess);
3082 CloseHandle(pi.hThread);
3083 CloseHandle(job);
3084 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
3085 return;
3086 }
3087
3088 /* the object is not reset immediately */
3089 dwret = WaitForSingleObject(job, 100);
3090 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret);
3091
3092 CloseHandle(pi.hProcess);
3093 CloseHandle(pi.hThread);
3094
3095 /* creating a new process doesn't reset the signalled state */
3096 create_process("wait", &pi);
3097
3098 ret = pAssignProcessToJobObject(job, pi.hProcess);
3099 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
3100
3101 dwret = WaitForSingleObject(job, 100);
3102 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret);
3103
3104 ret = pTerminateJobObject(job, 123);
3105 ok(ret, "TerminateJobObject error %lu\n", GetLastError());
3106
3107 CloseHandle(pi.hProcess);
3108 CloseHandle(pi.hThread);
3109
3110 CloseHandle(job);
3111
3112 /* repeat the test, but this time the process terminates properly */
3113 job = pCreateJobObjectW(NULL, NULL);
3114 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
3115
3116 dwret = WaitForSingleObject(job, 100);
3117 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret);
3118
3119 sprintf(buffer, "sync kernel32-process-%lx", GetCurrentProcessId());
3120 sem = CreateSemaphoreA(NULL, 0, 1, buffer + 5);
3121 ok(sem != NULL, "CreateSemaphoreA failed le=%lu\n", GetLastError());
3122 create_process(buffer, &pi);
3123
3124 ret = pAssignProcessToJobObject(job, pi.hProcess);
3125 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
3126 ReleaseSemaphore(sem, 1, NULL);
3127
3128 dwret = WaitForSingleObject(job, 100);
3129 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret);
3130
3131 wait_and_close_child_process(&pi);
3132 CloseHandle(job);
3133 CloseHandle(sem);
3134}
3135
3136static HANDLE test_AddSelfToJob(void)
3137{
3138 HANDLE job;
3139 BOOL ret;
3140
3141 job = pCreateJobObjectW(NULL, NULL);
3142 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
3143
3144 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
3145 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
3146 test_assigned_proc(job, 1, GetCurrentProcessId());
3147 test_accounting(job, 1, 1, 0);
3148
3149 return job;
3150}
3151
3152static void test_jobInheritance(HANDLE job)
3153{
3154 PROCESS_INFORMATION pi;
3155 BOOL ret, out;
3156
3157 if (!pIsProcessInJob)
3158 {
3159 win_skip("IsProcessInJob not available.\n");
3160 return;
3161 }
3162
3163 create_process("exit", &pi);
3164
3165 out = FALSE;
3166 ret = pIsProcessInJob(pi.hProcess, job, &out);
3167 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3168 ok(out, "IsProcessInJob returned out=%u\n", out);
3169 test_assigned_proc(job, 2, GetCurrentProcessId(), pi.dwProcessId);
3170 test_accounting(job, 2, 2, 0);
3171
3172 wait_and_close_child_process(&pi);
3173}
3174
3175static void test_BreakawayOk(HANDLE parent_job)
3176{
3177 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
3178 PROCESS_INFORMATION pi;
3179 STARTUPINFOA si = {0};
3180 char buffer[MAX_PATH + 23];
3181 BOOL ret, out, nested_jobs;
3182 HANDLE job;
3183
3184 if (!pIsProcessInJob)
3185 {
3186 win_skip("IsProcessInJob not available.\n");
3187 return;
3188 }
3189
3190 job = pCreateJobObjectW(NULL, NULL);
3191 ok(!!job, "CreateJobObjectW error %lu\n", GetLastError());
3192
3193 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
3194 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED) /* before Win 8. */,
3195 "AssignProcessToJobObject error %lu\n", GetLastError());
3196 nested_jobs = ret;
3197 if (!ret)
3198 win_skip("Nested jobs are not supported.\n");
3199
3200 sprintf(buffer, "\"%s\" process exit", selfname);
3201 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
3202 ok(!ret, "CreateProcessA expected failure\n");
3203 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
3204
3205 if (ret)
3206 {
3207 TerminateProcess(pi.hProcess, 0);
3208 wait_and_close_child_process(&pi);
3209 }
3210
3211 if (nested_jobs)
3212 {
3213 test_assigned_proc(job, 1, GetCurrentProcessId());
3214 test_accounting(job, 1, 1, 0);
3215
3216 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
3217 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3218 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
3219
3220 sprintf(buffer, "\"%s\" process exit", selfname);
3221 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
3222 ok(ret, "CreateProcessA error %lu\n", GetLastError());
3223
3224 ret = pIsProcessInJob(pi.hProcess, job, &out);
3225 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3226 ok(!out, "IsProcessInJob returned out=%u\n", out);
3227
3228 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
3229 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3230 ok(out, "IsProcessInJob returned out=%u\n", out);
3231
3232 TerminateProcess(pi.hProcess, 0);
3233 wait_and_close_child_process(&pi);
3234 }
3235
3236 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
3237 ret = pSetInformationJobObject(parent_job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3238 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
3239
3240 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
3241 ok(ret, "CreateProcessA error %lu\n", GetLastError());
3242
3243 ret = pIsProcessInJob(pi.hProcess, job, &out);
3244 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3245 ok(!out, "IsProcessInJob returned out=%u\n", out);
3246 if (nested_jobs)
3247 {
3248 test_assigned_proc(job, 1, GetCurrentProcessId());
3249 test_accounting(job, 1, 1, 0);
3250 }
3251
3252 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
3253 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3254 ok(!out, "IsProcessInJob returned out=%u\n", out);
3255
3256 wait_and_close_child_process(&pi);
3257
3258 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
3259 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3260 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
3261
3262 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3263 ok(ret, "CreateProcess error %lu\n", GetLastError());
3264
3265 ret = pIsProcessInJob(pi.hProcess, job, &out);
3266 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3267 ok(!out, "IsProcessInJob returned out=%u\n", out);
3268 if (nested_jobs)
3269 {
3270 test_assigned_proc(job, 1, GetCurrentProcessId());
3271 test_accounting(job, 1, 1, 0);
3272 }
3273
3274 wait_and_close_child_process(&pi);
3275
3276 /* unset breakaway ok */
3277 limit_info.BasicLimitInformation.LimitFlags = 0;
3278 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3279 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
3280}
3281
3282/* copy an executable, but changing its subsystem */
3283static void copy_change_subsystem(const char* in, const char* out, DWORD subsyst)
3284{
3285 BOOL ret;
3286 HANDLE hFile, hMap;
3287 void* mapping;
3288 IMAGE_NT_HEADERS *nthdr;
3289
3290 ret = CopyFileA(in, out, FALSE);
3291 ok(ret, "Failed to copy executable %s in %s (%lu)\n", in, out, GetLastError());
3292
3293 hFile = CreateFileA(out, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
3294 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3295 ok(hFile != INVALID_HANDLE_VALUE, "Couldn't open file %s (%lu)\n", out, GetLastError());
3296 hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
3297 ok(hMap != NULL, "Couldn't create map (%lu)\n", GetLastError());
3298 mapping = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
3299 ok(mapping != NULL, "Couldn't map (%lu)\n", GetLastError());
3300 nthdr = RtlImageNtHeader(mapping);
3301 ok(nthdr != NULL, "Cannot get NT headers out of %s\n", out);
3302 if (nthdr) nthdr->OptionalHeader.Subsystem = subsyst;
3303 ret = UnmapViewOfFile(mapping);
3304 ok(ret, "Couldn't unmap (%lu)\n", GetLastError());
3305 CloseHandle(hMap);
3306 CloseHandle(hFile);
3307}
3308
3309#define H_CONSOLE 0
3310#define H_DISK 1
3311#define H_CHAR 2
3312#define H_PIPE 3
3313#define H_NULL 4
3314#define H_INVALID 5
3315#define H_DEVIL 6 /* unassigned handle */
3316
3317#define ARG_STD 0x80000000
3318#define ARG_STARTUPINFO 0x00000000
3319#define ARG_CP_INHERIT 0x40000000
3320#define ARG_HANDLE_INHERIT 0x20000000
3321#define ARG_HANDLE_PROTECT 0x10000000
3322#define ARG_HANDLE_MASK (~0xff000000)
3323
3324static BOOL check_run_child(const char *exec, DWORD flags, BOOL cp_inherit,
3325 STARTUPINFOA *si)
3326{
3327 PROCESS_INFORMATION info;
3328 char buffer[2 * MAX_PATH + 64];
3329 DWORD exit_code;
3330 BOOL res;
3331 DWORD ret;
3332
3333 get_file_name(resfile);
3334 sprintf(buffer, "\"%s\" process dump \"%s\"", exec, resfile);
3335
3336 res = CreateProcessA(NULL, buffer, NULL, NULL, cp_inherit, flags, NULL, NULL, si, &info);
3337 ok(res, "CreateProcess failed: %lu %s\n", GetLastError(), buffer);
3338 CloseHandle(info.hThread);
3339 ret = WaitForSingleObject(info.hProcess, 30000);
3340 ok(ret == WAIT_OBJECT_0, "Could not wait for the child process: %ld le=%lu\n",
3341 ret, GetLastError());
3342 res = GetExitCodeProcess(info.hProcess, &exit_code);
3343 ok(res && exit_code == 0, "Couldn't get exit_code\n");
3344 CloseHandle(info.hProcess);
3345 return res;
3346}
3347
3348static char std_handle_file[MAX_PATH];
3349
3350static BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HANDLE hstd[2] )
3351{
3352 SECURITY_ATTRIBUTES inherit_sa = { sizeof(inherit_sa), NULL, TRUE };
3353 SECURITY_ATTRIBUTES *psa;
3354 BOOL ret, needs_close = FALSE;
3355
3356 psa = (args & ARG_HANDLE_INHERIT) ? &inherit_sa : NULL;
3357
3358 memset(startup, 0, sizeof(*startup));
3359 startup->cb = sizeof(*startup);
3360
3361 switch (args & ARG_HANDLE_MASK)
3362 {
3363 case H_CONSOLE:
3364 hstd[0] = CreateFileA("CONIN$", GENERIC_READ, 0, psa, OPEN_EXISTING, 0, 0);
3365 ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to console\n");
3366 hstd[1] = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, psa, OPEN_EXISTING, 0, 0);
3367 ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to console\n");
3368 needs_close = TRUE;
3369 break;
3370 case H_DISK:
3371 hstd[0] = CreateFileA(std_handle_file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, psa, OPEN_EXISTING, 0, 0);
3372 ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file);
3373 hstd[1] = CreateFileA(std_handle_file, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, psa, OPEN_EXISTING, 0, 0);
3374 ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file);
3375 needs_close = TRUE;
3376 break;
3377 case H_CHAR:
3378 hstd[0] = CreateFileA("NUL", GENERIC_READ, 0, psa, OPEN_EXISTING, 0, 0);
3379 ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to NUL\n");
3380 hstd[1] = CreateFileA("NUL", GENERIC_READ|GENERIC_WRITE, 0, psa, OPEN_EXISTING, 0, 0);
3381 ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to NUL\n");
3382 needs_close = TRUE;
3383 break;
3384 case H_PIPE:
3385 ret = CreatePipe(&hstd[0], &hstd[1], psa, 0);
3386 ok(ret, "Couldn't create anon pipe\n");
3387 needs_close = TRUE;
3388 break;
3389 case H_NULL:
3390 hstd[0] = hstd[1] = NULL;
3391 break;
3392 case H_INVALID:
3393 hstd[0] = hstd[1] = INVALID_HANDLE_VALUE;
3394 break;
3395 case H_DEVIL:
3396 hstd[0] = (HANDLE)(ULONG_PTR)0x066600;
3397 hstd[1] = (HANDLE)(ULONG_PTR)0x066610;
3398 break;
3399 default:
3400 ok(0, "Unsupported handle type %x\n", args & ARG_HANDLE_MASK);
3401 return FALSE;
3402 }
3403 if ((args & ARG_HANDLE_PROTECT) && needs_close)
3404 {
3405 ret = SetHandleInformation(hstd[0], HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
3406 ok(ret, "Couldn't set inherit flag to hstd[0]\n");
3407 ret = SetHandleInformation(hstd[1], HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
3408 ok(ret, "Couldn't set inherit flag to hstd[1]\n");
3409 }
3410
3411 if (args & ARG_STD)
3412 {
3413 SetStdHandle(STD_INPUT_HANDLE, hstd[0]);
3414 SetStdHandle(STD_OUTPUT_HANDLE, hstd[1]);
3415 }
3416 else /* through startup info */
3417 {
3418 startup->dwFlags |= STARTF_USESTDHANDLES;
3419 startup->hStdInput = hstd[0];
3420 startup->hStdOutput = hstd[1];
3421 }
3422 return needs_close;
3423}
3424
3425struct std_handle_test
3426{
3427 /* input */
3428 unsigned args;
3429 /* output */
3430 DWORD expected;
3431 DWORD is_broken; /* Win7 broken file types */
3432};
3433
3434static void test_StdHandleInheritance(void)
3435{
3436 HANDLE hsavestd[3];
3437 static char guiexec[MAX_PATH];
3438 static char cuiexec[MAX_PATH];
3439 char **argv;
3440 BOOL ret;
3441 int i, j;
3442
3443 static const struct std_handle_test
3444 nothing_cui[] =
3445 {
3446 /* all others handles type behave as H_DISK */
3447/* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
3448 {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
3449
3450 /* all others handles type behave as H_DISK */
3451 {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3452 {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
3453
3454 /* all others handles type behave as H_DISK */
3455 {ARG_STARTUPINFO | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3456/* 5*/ {ARG_STD | H_DISK, HATTR_TYPE | FILE_TYPE_DISK},
3457
3458 /* all others handles type behave as H_DISK */
3459 {ARG_STARTUPINFO | ARG_HANDLE_PROTECT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3460 {ARG_STD | ARG_HANDLE_PROTECT | H_DISK, HATTR_TYPE | HATTR_PROTECT | FILE_TYPE_DISK},
3461
3462 /* all others handles type behave as H_DISK */
3463 {ARG_STARTUPINFO | ARG_CP_INHERIT | H_DISK, HATTR_DANGLING, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3464 {ARG_STD | ARG_CP_INHERIT | H_DISK, HATTR_DANGLING},
3465
3466 /* all others handles type behave as H_DISK */
3467/*10*/ {ARG_STARTUPINFO | H_DEVIL, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3468 {ARG_STD | H_DEVIL, HATTR_NULL},
3469 {ARG_STARTUPINFO | H_INVALID, HATTR_NULL, .is_broken = HATTR_INVALID},
3470 {ARG_STD | H_INVALID, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3471 {ARG_STARTUPINFO | H_NULL, HATTR_NULL, .is_broken = HATTR_INVALID},
3472/*15*/ {ARG_STD | H_NULL, HATTR_NULL, .is_broken = HATTR_INVALID},
3473 },
3474 nothing_gui[] =
3475 {
3476 /* testing all types because of discrepancies */
3477/* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
3478 {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
3479 {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE},
3480 {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE},
3481 {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR},
3482/* 5*/ {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR},
3483 {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3484 {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3485
3486 /* all others handles type behave as H_DISK */
3487 {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3488 {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL},
3489
3490 /* all others handles type behave as H_DISK */
3491/*10*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | H_DISK, HATTR_DANGLING},
3492 {ARG_STD | ARG_CP_INHERIT | H_DISK, HATTR_DANGLING},
3493
3494 /* all others handles type behave as H_DISK */
3495 {ARG_STARTUPINFO | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3496 {ARG_STD | H_DISK, HATTR_NULL},
3497
3498 {ARG_STARTUPINFO | H_DEVIL, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3499/*15*/ {ARG_STD | H_DEVIL, HATTR_NULL},
3500 {ARG_STARTUPINFO | H_INVALID, HATTR_NULL, .is_broken = HATTR_INVALID},
3501 {ARG_STD | H_INVALID, HATTR_NULL},
3502 {ARG_STARTUPINFO | H_NULL, HATTR_NULL},
3503 {ARG_STD | H_NULL, HATTR_NULL},
3504 },
3505 detached_cui[] =
3506 {
3507 {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL},
3508 {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3509 /* all others handles type behave as H_DISK */
3510 {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL},
3511 {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
3512 },
3513 detached_gui[] =
3514 {
3515 {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL},
3516 {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
3517 /* all others handles type behave as H_DISK */
3518 {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL},
3519 {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
3520 };
3521 static const struct
3522 {
3523 DWORD cp_flags;
3524 BOOL use_cui;
3525 const struct std_handle_test* tests;
3526 size_t count;
3527 const char* descr;
3528 }
3529 tests[] =
3530 {
3531#define X(d, cg, s) {(d), (cg), s, ARRAY_SIZE(s), #s}
3532 X(0, TRUE, nothing_cui),
3533 X(0, FALSE, nothing_gui),
3534 X(DETACHED_PROCESS, TRUE, detached_cui),
3535 X(DETACHED_PROCESS, FALSE, detached_gui),
3536#undef X
3537 };
3538
3539#ifdef __REACTOS__
3540 if (is_reactos()) {
3541 ok(FALSE, "FIXME: These std handle tests on ReactOS confuses rosautotest\n");
3542 return;
3543 }
3544#endif
3545 hsavestd[0] = GetStdHandle(STD_INPUT_HANDLE);
3546 hsavestd[1] = GetStdHandle(STD_OUTPUT_HANDLE);
3547 hsavestd[2] = GetStdHandle(STD_ERROR_HANDLE);
3548
3549 winetest_get_mainargs(&argv);
3550
3551 GetTempPathA(ARRAY_SIZE(guiexec), guiexec);
3552 strcat(guiexec, "process_gui.exe");
3553 copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI);
3554 GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec);
3555 strcat(cuiexec, "process_cui.exe");
3556 copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI);
3557 get_file_name(std_handle_file);
3558
3559 for (j = 0; j < ARRAY_SIZE(tests); j++)
3560 {
3561 const struct std_handle_test* std_tests = tests[j].tests;
3562
3563 for (i = 0; i < tests[j].count; i++)
3564 {
3565 STARTUPINFOA startup;
3566#if defined(__REACTOS__) && defined(_MSC_VER)
3567 HANDLE hstd[2] = {0};
3568#else
3569 HANDLE hstd[2] = {};
3570#endif
3571 BOOL needs_close;
3572
3573 winetest_push_context("%s[%u] ", tests[j].descr, i);
3574 needs_close = build_startupinfo( &startup, std_tests[i].args, hstd );
3575
3576 ret = check_run_child(tests[j].use_cui ? cuiexec : guiexec,
3577 tests[j].cp_flags, !!(std_tests[i].args & ARG_CP_INHERIT),
3578 &startup);
3579 ok(ret, "Couldn't run child\n");
3580 reload_child_info(resfile);
3581
3582 if (std_tests[i].expected & HATTR_DANGLING)
3583 {
3584 /* The value of the handle (in parent) has been copied in STARTUPINFO fields (in child),
3585 * but the object hasn't been inherited from parent to child.
3586 * There's no reliable way to test that the object hasn't been inherited, as the
3587 * entry in the child's handle table is free and could have been reused before
3588 * this test occurs.
3589 * So simply test that the value is passed untouched.
3590 */
3591 okChildHexInt("StartupInfoA", "hStdInput", (DWORD_PTR)((std_tests[i].args & ARG_STD) ? INVALID_HANDLE_VALUE : hstd[0]), std_tests[i].is_broken);
3592 okChildHexInt("StartupInfoA", "hStdOutput", (DWORD_PTR)((std_tests[i].args & ARG_STD) ? INVALID_HANDLE_VALUE : hstd[1]), std_tests[i].is_broken);
3593 if (!(std_tests[i].args & ARG_STD))
3594 {
3595 okChildHexInt("StartupInfoW", "hStdInput", (DWORD_PTR)hstd[0], std_tests[i].is_broken);
3596 okChildHexInt("StartupInfoW", "hStdOutput", (DWORD_PTR)hstd[1], std_tests[i].is_broken);
3597 }
3598
3599 okChildHexInt("TEB", "hStdInput", (DWORD_PTR)hstd[0], std_tests[i].is_broken);
3600 okChildHexInt("TEB", "hStdOutput", (DWORD_PTR)hstd[1], std_tests[i].is_broken);
3601 }
3602 else
3603 {
3604 unsigned startup_expected = (std_tests[i].args & ARG_STD) ? HATTR_INVALID : std_tests[i].expected;
3605
3606 okChildHexInt("StartupInfoA", "hStdInputEncode", startup_expected, std_tests[i].is_broken);
3607 okChildHexInt("StartupInfoA", "hStdOutputEncode", startup_expected, std_tests[i].is_broken);
3608
3609 startup_expected = (std_tests[i].args & ARG_STD) ? HATTR_UNTOUCHED : std_tests[i].expected;
3610
3611 okChildHexInt("StartupInfoW", "hStdInputEncode", startup_expected, std_tests[i].is_broken);
3612 okChildHexInt("StartupInfoW", "hStdOutputEncode", startup_expected, std_tests[i].is_broken);
3613
3614#ifdef __REACTOS__
3615 if (GetNTVersion() >= _WIN32_WINNT_VISTA) {
3616#endif
3617 okChildHexInt("TEB", "hStdInputEncode", std_tests[i].expected, std_tests[i].is_broken);
3618 okChildHexInt("TEB", "hStdOutputEncode", std_tests[i].expected, std_tests[i].is_broken);
3619#ifdef __REACTOS__
3620 }
3621#endif
3622 }
3623
3624 release_memory();
3625 DeleteFileA(resfile);
3626 if (needs_close)
3627 {
3628 SetHandleInformation(hstd[0], HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
3629 CloseHandle(hstd[0]);
3630 SetHandleInformation(hstd[1], HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
3631 CloseHandle(hstd[1]);
3632 }
3633 winetest_pop_context();
3634 }
3635 }
3636
3637 DeleteFileA(guiexec);
3638 DeleteFileA(cuiexec);
3639 DeleteFileA(std_handle_file);
3640
3641 SetStdHandle(STD_INPUT_HANDLE, hsavestd[0]);
3642 SetStdHandle(STD_OUTPUT_HANDLE, hsavestd[1]);
3643 SetStdHandle(STD_ERROR_HANDLE, hsavestd[2]);
3644}
3645
3646#if defined(__i386__) || defined(__x86_64__)
3647static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi,
3648 IMAGE_NT_HEADERS *nt_header)
3649{
3650 IMAGE_DOS_HEADER dos_header;
3651
3652 if (!ReadProcessMemory(process_handle, mbi->BaseAddress, &dos_header, sizeof(dos_header), NULL))
3653 return FALSE;
3654
3655 if ((dos_header.e_magic != IMAGE_DOS_SIGNATURE) ||
3656 ((ULONG)dos_header.e_lfanew > mbi->RegionSize) ||
3657 (dos_header.e_lfanew < sizeof(dos_header)))
3658 return FALSE;
3659
3660 if (!ReadProcessMemory(process_handle, (char *)mbi->BaseAddress + dos_header.e_lfanew,
3661 nt_header, sizeof(*nt_header), NULL))
3662 return FALSE;
3663
3664 return (nt_header->Signature == IMAGE_NT_SIGNATURE);
3665}
3666
3667static PVOID get_process_exe(HANDLE process_handle, IMAGE_NT_HEADERS *nt_header)
3668{
3669 PVOID exe_base, address;
3670 MEMORY_BASIC_INFORMATION mbi;
3671
3672 /* Find the EXE base in the new process */
3673 exe_base = NULL;
3674 for (address = NULL ;
3675 VirtualQueryEx(process_handle, address, &mbi, sizeof(mbi)) ;
3676 address = (char *)mbi.BaseAddress + mbi.RegionSize) {
3677 if ((mbi.Type == SEC_IMAGE) &&
3678 read_nt_header(process_handle, &mbi, nt_header) &&
3679 !(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
3680 exe_base = mbi.BaseAddress;
3681 break;
3682 }
3683 }
3684
3685 return exe_base;
3686}
3687
3688static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE_NT_HEADERS *nt_header)
3689{
3690 BOOL ret;
3691 IMAGE_IMPORT_DESCRIPTOR iid;
3692 ULONG_PTR orig_iat_entry_value, iat_entry_value;
3693
3694 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, "Import table VA is zero\n");
3695 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, "Import table Size is zero\n");
3696
3697 if (!nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ||
3698 !nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
3699 return FALSE;
3700
3701 /* Read the first IID */
3702 ret = ReadProcessMemory(process_handle,
3703 (char *)module_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
3704 &iid, sizeof(iid), NULL);
3705 ok(ret, "Failed to read remote module IID (%ld)\n", GetLastError());
3706
3707 /* Validate the IID is present and not a bound import, and that we have
3708 an OriginalFirstThunk to compare with */
3709 ok(iid.Name, "Module first IID does not have a Name\n");
3710 ok(iid.FirstThunk, "Module first IID does not have a FirstThunk\n");
3711 ok(!iid.TimeDateStamp, "Module first IID is a bound import (UNSUPPORTED for current test)\n");
3712 ok(iid.OriginalFirstThunk, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3713
3714 /* Read a single IAT entry from the FirstThunk */
3715 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.FirstThunk,
3716 &iat_entry_value, sizeof(iat_entry_value), NULL);
3717 ok(ret, "Failed to read IAT entry from FirstThunk (%ld)\n", GetLastError());
3718 ok(iat_entry_value, "IAT entry in FirstThunk is NULL\n");
3719
3720 /* Read a single IAT entry from the OriginalFirstThunk */
3721 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.OriginalFirstThunk,
3722 &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL);
3723 ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%ld)\n", GetLastError());
3724 ok(orig_iat_entry_value, "IAT entry in OriginalFirstThunk is NULL\n");
3725
3726 return iat_entry_value != orig_iat_entry_value;
3727}
3728
3729static void test_SuspendProcessNewThread(void)
3730{
3731 BOOL ret;
3732 STARTUPINFOA si = {0};
3733 PROCESS_INFORMATION pi = {0};
3734 PVOID exe_base, exit_thread_ptr;
3735 IMAGE_NT_HEADERS nt_header;
3736 HANDLE thread_handle = NULL;
3737 DWORD dret, exit_code = 0;
3738 CONTEXT ctx;
3739
3740 exit_thread_ptr = GetProcAddress(hkernel32, "ExitThread");
3741 ok(exit_thread_ptr != NULL, "GetProcAddress ExitThread failed\n");
3742
3743 si.cb = sizeof(si);
3744 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3745 ok(ret, "Failed to create process (%ld)\n", GetLastError());
3746
3747 exe_base = get_process_exe(pi.hProcess, &nt_header);
3748 ok(exe_base != NULL, "Could not find EXE in remote process\n");
3749
3750 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3751 ok(!ret, "IAT entry resolved prematurely\n");
3752
3753 thread_handle = CreateRemoteThread(pi.hProcess, NULL, 0,
3754 (LPTHREAD_START_ROUTINE)exit_thread_ptr,
3755 (PVOID)(ULONG_PTR)0x1234, CREATE_SUSPENDED, NULL);
3756 ok(thread_handle != NULL, "Could not create remote thread (%ld)\n", GetLastError());
3757
3758 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3759 ok(!ret, "IAT entry resolved prematurely\n");
3760
3761 ctx.ContextFlags = CONTEXT_ALL;
3762 ret = GetThreadContext( thread_handle, &ctx );
3763 ok( ret, "Failed retrieving remote thread context (%ld)\n", GetLastError() );
3764 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %lx\n", ctx.ContextFlags );
3765#ifdef __x86_64__
3766 ok( !ctx.Rax, "rax is not zero %Ix\n", ctx.Rax );
3767 ok( !ctx.Rbx, "rbx is not zero %Ix\n", ctx.Rbx );
3768 ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %Ix/%p\n", ctx.Rcx, exit_thread_ptr );
3769 ok( ctx.Rdx == 0x1234, "wrong rdx %Ix\n", ctx.Rdx );
3770 ok( !ctx.Rsi, "rsi is not zero %Ix\n", ctx.Rsi );
3771 ok( !ctx.Rdi, "rdi is not zero %Ix\n", ctx.Rdi );
3772 ok( !ctx.Rbp, "rbp is not zero %Ix\n", ctx.Rbp );
3773 ok( !ctx.R8, "r8 is not zero %Ix\n", ctx.R8 );
3774 ok( !ctx.R9, "r9 is not zero %Ix\n", ctx.R9 );
3775 ok( !ctx.R10, "r10 is not zero %Ix\n", ctx.R10 );
3776 ok( !ctx.R11, "r11 is not zero %Ix\n", ctx.R11 );
3777 ok( !ctx.R12, "r12 is not zero %Ix\n", ctx.R12 );
3778 ok( !ctx.R13, "r13 is not zero %Ix\n", ctx.R13 );
3779 ok( !ctx.R14, "r14 is not zero %Ix\n", ctx.R14 );
3780 ok( !ctx.R15, "r15 is not zero %Ix\n", ctx.R15 );
3781 ok( ctx.EFlags == 0x200, "wrong flags %08lx\n", ctx.EFlags );
3782 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08lx\n", ctx.MxCsr );
3783 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3784#else
3785 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08lx\n", ctx.Ebp );
3786 if (!ctx.Ebp) /* winxp is completely different */
3787 {
3788 ok( !ctx.Ecx, "ecx is not zero %08lx\n", ctx.Ecx );
3789 ok( !ctx.Edx, "edx is not zero %08lx\n", ctx.Edx );
3790 ok( !ctx.Esi, "esi is not zero %08lx\n", ctx.Esi );
3791 ok( !ctx.Edi, "edi is not zero %08lx\n", ctx.Edi );
3792 }
3793 ok( ctx.Eax == (ULONG_PTR)exit_thread_ptr, "wrong eax %08lx/%p\n", ctx.Eax, exit_thread_ptr );
3794 ok( ctx.Ebx == 0x1234, "wrong ebx %08lx\n", ctx.Ebx );
3795 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08lx\n", ctx.EFlags );
3796 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08lx\n", ctx.FloatSave.ControlWord );
3797 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3798#endif
3799
3800 ResumeThread( thread_handle );
3801 dret = WaitForSingleObject(thread_handle, 60000);
3802 ok(dret == WAIT_OBJECT_0, "Waiting for remote thread failed (%ld)\n", GetLastError());
3803 ret = GetExitCodeThread(thread_handle, &exit_code);
3804 ok(ret, "Failed to retrieve remote thread exit code (%ld)\n", GetLastError());
3805 ok(exit_code == 0x1234, "Invalid remote thread exit code\n");
3806
3807 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3808 ok(ret, "EXE IAT entry not resolved\n");
3809
3810 if (thread_handle)
3811 CloseHandle(thread_handle);
3812
3813 /* Note that the child's main thread is still suspended so the exit code
3814 * is set by the TerminateProcess() call.
3815 */
3816 TerminateProcess(pi.hProcess, 0);
3817 wait_and_close_child_process(&pi);
3818}
3819
3820static void test_SuspendProcessState(void)
3821{
3822 struct pipe_params
3823 {
3824 ULONG pipe_write_buf;
3825 ULONG pipe_read_buf;
3826 ULONG bytes_returned;
3827 CHAR pipe_name[MAX_PATH];
3828 };
3829
3830#ifdef __x86_64__
3831 struct remote_rop_chain
3832 {
3833 void *exit_process_ptr;
3834 ULONG_PTR home_rcx;
3835 ULONG_PTR home_rdx;
3836 ULONG_PTR home_r8;
3837 ULONG_PTR home_r9;
3838 ULONG_PTR pipe_read_buf_size;
3839 ULONG_PTR bytes_returned;
3840 ULONG_PTR timeout;
3841 };
3842#else
3843 struct remote_rop_chain
3844 {
3845 void *exit_process_ptr;
3846 ULONG_PTR pipe_name;
3847 ULONG_PTR pipe_write_buf;
3848 ULONG_PTR pipe_write_buf_size;
3849 ULONG_PTR pipe_read_buf;
3850 ULONG_PTR pipe_read_buf_size;
3851 ULONG_PTR bytes_returned;
3852 ULONG_PTR timeout;
3853 void *unreached_ret;
3854 ULONG_PTR exit_code;
3855 };
3856#endif
3857
3858 static const char pipe_name[] = "\\\\.\\pipe\\TestPipe";
3859 static const ULONG pipe_write_magic = 0x454e4957;
3860 STARTUPINFOA si = {0};
3861 PROCESS_INFORMATION pi = {0};
3862 PVOID exe_base, remote_pipe_params, exit_process_ptr,
3863 call_named_pipe_a;
3864 IMAGE_NT_HEADERS nt_header;
3865 struct pipe_params pipe_params;
3866 struct remote_rop_chain rop_chain;
3867 CONTEXT ctx;
3868 HANDLE server_pipe_handle;
3869 BOOL pipe_connected;
3870 ULONG pipe_magic, numb;
3871 BOOL ret;
3872 void *user_thread_start, *start_ptr, *entry_ptr, *peb_ptr;
3873 PEB child_peb, *peb = NtCurrentTeb()->Peb;
3874
3875 exit_process_ptr = GetProcAddress(hkernel32, "ExitProcess");
3876 ok(exit_process_ptr != NULL, "GetProcAddress ExitProcess failed\n");
3877
3878 call_named_pipe_a = GetProcAddress(hkernel32, "CallNamedPipeA");
3879 ok(call_named_pipe_a != NULL, "GetProcAddress CallNamedPipeA failed\n");
3880
3881 si.cb = sizeof(si);
3882 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3883 ok(ret, "Failed to create process (%ld)\n", GetLastError());
3884
3885 exe_base = get_process_exe(pi.hProcess, &nt_header);
3886 /* Make sure we found the EXE in the new process */
3887 ok(exe_base != NULL, "Could not find EXE in remote process\n");
3888
3889 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3890 ok(!ret, "IAT entry resolved prematurely\n");
3891
3892 server_pipe_handle = CreateNamedPipeA(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH,
3893 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0x20000, 0x20000,
3894 0, NULL);
3895 ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%ld)\n", GetLastError());
3896
3897 /* Set up the remote process environment */
3898 ctx.ContextFlags = CONTEXT_ALL;
3899 ret = GetThreadContext(pi.hThread, &ctx);
3900 ok(ret, "Failed retrieving remote thread context (%ld)\n", GetLastError());
3901 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %lx\n", ctx.ContextFlags );
3902
3903 remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE);
3904 ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%ld)\n", GetLastError());
3905
3906 pipe_params.pipe_write_buf = pipe_write_magic;
3907 pipe_params.pipe_read_buf = 0;
3908 pipe_params.bytes_returned = 0;
3909 strcpy(pipe_params.pipe_name, pipe_name);
3910
3911 ret = WriteProcessMemory(pi.hProcess, remote_pipe_params,
3912 &pipe_params, sizeof(pipe_params), NULL);
3913 ok(ret, "Failed to write to remote process memory (%ld)\n", GetLastError());
3914
3915#ifdef __x86_64__
3916 ok( !ctx.Rax, "rax is not zero %Ix\n", ctx.Rax );
3917 ok( !ctx.Rbx, "rbx is not zero %Ix\n", ctx.Rbx );
3918 ok( !ctx.Rsi, "rsi is not zero %Ix\n", ctx.Rsi );
3919 ok( !ctx.Rdi, "rdi is not zero %Ix\n", ctx.Rdi );
3920 ok( !ctx.Rbp, "rbp is not zero %Ix\n", ctx.Rbp );
3921 ok( !ctx.R8, "r8 is not zero %Ix\n", ctx.R8 );
3922 ok( !ctx.R9, "r9 is not zero %Ix\n", ctx.R9 );
3923 ok( !ctx.R10, "r10 is not zero %Ix\n", ctx.R10 );
3924 ok( !ctx.R11, "r11 is not zero %Ix\n", ctx.R11 );
3925 ok( !ctx.R12, "r12 is not zero %Ix\n", ctx.R12 );
3926 ok( !ctx.R13, "r13 is not zero %Ix\n", ctx.R13 );
3927 ok( !ctx.R14, "r14 is not zero %Ix\n", ctx.R14 );
3928 ok( !ctx.R15, "r15 is not zero %Ix\n", ctx.R15 );
3929 ok( ctx.EFlags == 0x200, "wrong flags %08lx\n", ctx.EFlags );
3930 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08lx\n", ctx.MxCsr );
3931 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3932 start_ptr = (void *)ctx.Rip;
3933 entry_ptr = (void *)ctx.Rcx;
3934 peb_ptr = (void *)ctx.Rdx;
3935
3936 rop_chain.exit_process_ptr = exit_process_ptr;
3937 ctx.Rcx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3938 ctx.Rdx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3939 ctx.R8 = sizeof(pipe_params.pipe_write_buf);
3940 ctx.R9 = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3941 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3942 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3943 rop_chain.timeout = 10000;
3944
3945 ctx.Rip = (ULONG_PTR)call_named_pipe_a;
3946 ctx.Rsp -= sizeof(rop_chain);
3947 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL);
3948 ok(ret, "Failed to write to remote process thread stack (%ld)\n", GetLastError());
3949#else
3950 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08lx\n", ctx.Ebp );
3951 if (!ctx.Ebp) /* winxp is completely different */
3952 {
3953 ok( !ctx.Ecx, "ecx is not zero %08lx\n", ctx.Ecx );
3954 ok( !ctx.Edx, "edx is not zero %08lx\n", ctx.Edx );
3955 ok( !ctx.Esi, "esi is not zero %08lx\n", ctx.Esi );
3956 ok( !ctx.Edi, "edi is not zero %08lx\n", ctx.Edi );
3957 }
3958 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08lx\n", ctx.EFlags );
3959 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08lx\n", ctx.FloatSave.ControlWord );
3960 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3961 start_ptr = (void *)ctx.Eip;
3962 entry_ptr = (void *)ctx.Eax;
3963 peb_ptr = (void *)ctx.Ebx;
3964
3965 rop_chain.exit_process_ptr = exit_process_ptr;
3966 rop_chain.pipe_name = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3967 rop_chain.pipe_write_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3968 rop_chain.pipe_write_buf_size = sizeof(pipe_params.pipe_write_buf);
3969 rop_chain.pipe_read_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3970 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3971 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3972 rop_chain.timeout = 10000;
3973 rop_chain.exit_code = 0;
3974
3975 ctx.Eip = (ULONG_PTR)call_named_pipe_a;
3976 ctx.Esp -= sizeof(rop_chain);
3977 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Esp, &rop_chain, sizeof(rop_chain), NULL);
3978 ok(ret, "Failed to write to remote process thread stack (%ld)\n", GetLastError());
3979#endif
3980
3981 ret = ReadProcessMemory( pi.hProcess, peb_ptr, &child_peb, sizeof(child_peb), NULL );
3982 ok( ret, "Failed to read PEB (%lu)\n", GetLastError() );
3983 ok( child_peb.ImageBaseAddress == exe_base, "wrong base %p/%p\n",
3984 child_peb.ImageBaseAddress, exe_base );
3985 user_thread_start = GetProcAddress( GetModuleHandleA("ntdll.dll"), "RtlUserThreadStart" );
3986 if (user_thread_start)
3987 ok( start_ptr == user_thread_start,
3988 "wrong start addr %p / %p\n", start_ptr, user_thread_start );
3989 ok( entry_ptr == (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint,
3990 "wrong entry point %p/%p\n", entry_ptr,
3991 (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint );
3992
3993 ok( !child_peb.LdrData, "LdrData set %p\n", child_peb.LdrData );
3994 ok( !child_peb.FastPebLock, "FastPebLock set %p\n", child_peb.FastPebLock );
3995 ok( !child_peb.TlsBitmap, "TlsBitmap set %p\n", child_peb.TlsBitmap );
3996 ok( !child_peb.TlsExpansionBitmap, "TlsExpansionBitmap set %p\n", child_peb.TlsExpansionBitmap );
3997 ok( !child_peb.LoaderLock, "LoaderLock set %p\n", child_peb.LoaderLock );
3998 ok( !child_peb.ProcessHeap, "ProcessHeap set %p\n", child_peb.ProcessHeap );
3999 ok( !child_peb.CSDVersion.Buffer, "CSDVersion set %s\n", debugstr_w(child_peb.CSDVersion.Buffer) );
4000
4001 ok( child_peb.OSMajorVersion == peb->OSMajorVersion, "OSMajorVersion not set %lu\n", child_peb.OSMajorVersion );
4002 ok( child_peb.OSPlatformId == peb->OSPlatformId, "OSPlatformId not set %lu\n", child_peb.OSPlatformId );
4003 ok( child_peb.SessionId == peb->SessionId, "SessionId not set %lu\n", child_peb.SessionId );
4004 ok( child_peb.CriticalSectionTimeout.QuadPart, "CriticalSectionTimeout not set %s\n",
4005 wine_dbgstr_longlong(child_peb.CriticalSectionTimeout.QuadPart) );
4006 ok( child_peb.HeapSegmentReserve == peb->HeapSegmentReserve,
4007 "HeapSegmentReserve not set %Iu\n", child_peb.HeapSegmentReserve );
4008 ok( child_peb.HeapSegmentCommit == peb->HeapSegmentCommit,
4009 "HeapSegmentCommit not set %Iu\n", child_peb.HeapSegmentCommit );
4010 ok( child_peb.HeapDeCommitTotalFreeThreshold == peb->HeapDeCommitTotalFreeThreshold,
4011 "HeapDeCommitTotalFreeThreshold not set %Iu\n", child_peb.HeapDeCommitTotalFreeThreshold );
4012 ok( child_peb.HeapDeCommitFreeBlockThreshold == peb->HeapDeCommitFreeBlockThreshold,
4013 "HeapDeCommitFreeBlockThreshold not set %Iu\n", child_peb.HeapDeCommitFreeBlockThreshold );
4014
4015 if (pNtQueryInformationThread)
4016 {
4017 TEB child_teb;
4018 THREAD_BASIC_INFORMATION info;
4019 NTSTATUS status = pNtQueryInformationThread( pi.hThread, ThreadBasicInformation,
4020 &info, sizeof(info), NULL );
4021 ok( !status, "NtQueryInformationProcess failed %lx\n", status );
4022 ret = ReadProcessMemory( pi.hProcess, info.TebBaseAddress, &child_teb, sizeof(child_teb), NULL );
4023 ok( ret, "Failed to read TEB (%lu)\n", GetLastError() );
4024
4025 ok( child_teb.Peb == peb_ptr, "wrong Peb %p / %p\n", child_teb.Peb, peb_ptr );
4026 ok( PtrToUlong(child_teb.ClientId.UniqueProcess) == pi.dwProcessId, "wrong pid %lx / %lx\n",
4027 PtrToUlong(child_teb.ClientId.UniqueProcess), pi.dwProcessId );
4028 ok( PtrToUlong(child_teb.ClientId.UniqueThread) == pi.dwThreadId, "wrong tid %lx / %lx\n",
4029 PtrToUlong(child_teb.ClientId.UniqueThread), pi.dwThreadId );
4030 ok( PtrToUlong(child_teb.RealClientId.UniqueProcess) == pi.dwProcessId, "wrong real pid %lx / %lx\n",
4031 PtrToUlong(child_teb.RealClientId.UniqueProcess), pi.dwProcessId );
4032 ok( PtrToUlong(child_teb.RealClientId.UniqueThread) == pi.dwThreadId, "wrong real tid %lx / %lx\n",
4033 PtrToUlong(child_teb.RealClientId.UniqueThread), pi.dwThreadId );
4034 ok( child_teb.StaticUnicodeString.MaximumLength == sizeof(child_teb.StaticUnicodeBuffer),
4035 "StaticUnicodeString.MaximumLength wrong %x\n", child_teb.StaticUnicodeString.MaximumLength );
4036 ok( (char *)child_teb.StaticUnicodeString.Buffer == (char *)info.TebBaseAddress + offsetof(TEB, StaticUnicodeBuffer),
4037 "StaticUnicodeString.Buffer wrong %p\n", child_teb.StaticUnicodeString.Buffer );
4038
4039 ok( !child_teb.CurrentLocale, "CurrentLocale set %lx\n", child_teb.CurrentLocale );
4040 ok( !child_teb.TlsLinks.Flink, "TlsLinks.Flink set %p\n", child_teb.TlsLinks.Flink );
4041 ok( !child_teb.TlsLinks.Blink, "TlsLinks.Blink set %p\n", child_teb.TlsLinks.Blink );
4042 ok( !child_teb.TlsExpansionSlots, "TlsExpansionSlots set %p\n", child_teb.TlsExpansionSlots );
4043 ok( !child_teb.FlsSlots, "FlsSlots set %p\n", child_teb.FlsSlots );
4044 }
4045
4046 ret = SetThreadContext(pi.hThread, &ctx);
4047 ok(ret, "Failed to set remote thread context (%ld)\n", GetLastError());
4048
4049 ResumeThread(pi.hThread);
4050
4051 pipe_connected = ConnectNamedPipe(server_pipe_handle, NULL) || (GetLastError() == ERROR_PIPE_CONNECTED);
4052 ok(pipe_connected, "Pipe did not connect\n");
4053
4054 ret = ReadFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
4055 ok(ret, "Failed to read buffer from pipe (%ld)\n", GetLastError());
4056
4057 ok(pipe_magic == pipe_write_magic, "Did not get the correct magic from the remote process\n");
4058
4059 /* Validate the imports: at this point the thread in the new process
4060 * should have initialized the EXE module imports and called each dll's
4061 * DllMain(), notifying it of the new thread in the process.
4062 */
4063 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
4064 ok(ret, "EXE IAT is not resolved\n");
4065
4066 ret = WriteFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
4067 ok(ret, "Failed to write the magic back to the pipe (%ld)\n", GetLastError());
4068 CloseHandle(server_pipe_handle);
4069
4070 /* Avoid wait_child_process() because the exit code results from a race
4071 * between the TerminateProcess() call and the child's ExitProcess() call
4072 * which uses a random value in the 64 bit case.
4073 */
4074 TerminateProcess(pi.hProcess, 0);
4075 WaitForSingleObject(pi.hProcess, 10000);
4076 CloseHandle(pi.hProcess);
4077 CloseHandle(pi.hThread);
4078}
4079#else
4080static void test_SuspendProcessNewThread(void)
4081{
4082}
4083static void test_SuspendProcessState(void)
4084{
4085}
4086#endif
4087
4088static void test_GetNumaProcessorNode(void)
4089{
4090 SYSTEM_INFO si;
4091 UCHAR node;
4092 BOOL ret;
4093 int i;
4094
4095 if (!pGetNumaProcessorNode)
4096 {
4097 win_skip("GetNumaProcessorNode is missing\n");
4098 return;
4099 }
4100
4101 GetSystemInfo(&si);
4102 for (i = 0; i < 256; i++)
4103 {
4104 SetLastError(0xdeadbeef);
4105 node = (i < si.dwNumberOfProcessors) ? 0xFF : 0xAA;
4106 ret = pGetNumaProcessorNode(i, &node);
4107 if (i < si.dwNumberOfProcessors)
4108 {
4109 ok(ret, "GetNumaProcessorNode returned FALSE for processor %d\n", i);
4110 ok(node != 0xFF, "expected node != 0xFF, but got 0xFF\n");
4111 }
4112 else
4113 {
4114 ok(!ret, "GetNumaProcessorNode returned TRUE for processor %d\n", i);
4115 ok(node == 0xFF || broken(node == 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node);
4116 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4117 }
4118 }
4119}
4120
4121static void test_session_info(void)
4122{
4123 DWORD session_id, active_session;
4124 BOOL r;
4125
4126 r = ProcessIdToSessionId(GetCurrentProcessId(), &session_id);
4127 ok(r, "ProcessIdToSessionId failed: %lu\n", GetLastError());
4128 trace("session_id = %lx\n", session_id);
4129
4130 active_session = pWTSGetActiveConsoleSessionId();
4131 trace("active_session = %lx\n", active_session);
4132}
4133
4134static void test_process_info(HANDLE hproc)
4135{
4136 char buf[4096];
4137 static const ULONG info_size[] =
4138 {
4139 sizeof(PROCESS_BASIC_INFORMATION) /* ProcessBasicInformation */,
4140 sizeof(QUOTA_LIMITS) /* ProcessQuotaLimits */,
4141 sizeof(IO_COUNTERS) /* ProcessIoCounters */,
4142 sizeof(VM_COUNTERS) /* ProcessVmCounters */,
4143 sizeof(KERNEL_USER_TIMES) /* ProcessTimes */,
4144 sizeof(ULONG) /* ProcessBasePriority */,
4145 sizeof(ULONG) /* ProcessRaisePriority */,
4146 sizeof(HANDLE) /* ProcessDebugPort */,
4147 sizeof(HANDLE) /* ProcessExceptionPort */,
4148 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
4149 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
4150 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
4151 sizeof(ULONG) /* ProcessDefaultHardErrorMode */,
4152 0 /* ProcessIoPortHandlers: kernel-mode only */,
4153 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
4154 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
4155 sizeof(ULONG) /* ProcessUserModeIOPL */,
4156 sizeof(BOOLEAN) /* ProcessEnableAlignmentFaultFixup */,
4157 sizeof(PROCESS_PRIORITY_CLASS) /* ProcessPriorityClass */,
4158 sizeof(ULONG) /* ProcessWx86Information */,
4159 sizeof(ULONG) /* ProcessHandleCount */,
4160 sizeof(ULONG_PTR) /* ProcessAffinityMask */,
4161 sizeof(ULONG) /* ProcessPriorityBoost */,
4162 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
4163 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
4164 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
4165 sizeof(ULONG_PTR) /* ProcessWow64Information */,
4166 sizeof(buf) /* ProcessImageFileName */,
4167 sizeof(ULONG) /* ProcessLUIDDeviceMapsEnabled */,
4168 sizeof(ULONG) /* ProcessBreakOnTermination */,
4169 sizeof(HANDLE) /* ProcessDebugObjectHandle */,
4170 sizeof(ULONG) /* ProcessDebugFlags */,
4171 sizeof(buf) /* ProcessHandleTracing */,
4172 sizeof(ULONG) /* ProcessIoPriority */,
4173 sizeof(ULONG) /* ProcessExecuteFlags */,
4174 0 /* FIXME: sizeof(?) ProcessTlsInformation */,
4175 sizeof(ULONG) /* ProcessCookie */,
4176 sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */,
4177 sizeof(PROCESS_CYCLE_TIME_INFORMATION) /* ProcessCycleTime */,
4178 sizeof(ULONG) /* ProcessPagePriority */,
4179 40 /* ProcessInstrumentationCallback */,
4180 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
4181 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
4182 sizeof(buf) /* ProcessImageFileNameWin32 */,
4183#if 0 /* FIXME: Add remaining classes */
4184 sizeof(HANDLE) /* ProcessImageFileMapping */,
4185 sizeof(PROCESS_AFFINITY_UPDATE_MODE) /* ProcessAffinityUpdateMode */,
4186 sizeof(PROCESS_MEMORY_ALLOCATION_MODE) /* ProcessMemoryAllocationMode */,
4187 sizeof(USHORT[]) /* ProcessGroupInformation */,
4188 sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */,
4189 sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */,
4190 sizeof(PROCESS_WINDOW_INFORMATION) /* ProcessWindowInformation */,
4191 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */,
4192 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */,
4193 sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */,
4194 sizeof(?) /* ProcessHandleCheckingMode */,
4195 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION) /* ProcessKeepAliveCount */,
4196 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION) /* ProcessRevokeFileHandles */,
4197 sizeof(PROCESS_WORKING_SET_CONTROL) /* ProcessWorkingSetControl */,
4198 sizeof(?) /* ProcessHandleTable */,
4199 sizeof(?) /* ProcessCheckStackExtentsMode */,
4200 sizeof(buf) /* ProcessCommandLineInformation */,
4201 sizeof(PS_PROTECTION) /* ProcessProtectionInformation */,
4202 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO) /* ProcessMemoryExhaustion */,
4203 sizeof(PROCESS_FAULT_INFORMATION) /* ProcessFaultInformation */,
4204 sizeof(PROCESS_TELEMETRY_ID_INFORMATION) /* ProcessTelemetryIdInformation */,
4205 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION) /* ProcessCommitReleaseInformation */,
4206 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
4207 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
4208 0 /* ProcessReserved1Information */,
4209 0 /* ProcessReserved2Information */,
4210 sizeof(?) /* ProcessSubsystemProcess */,
4211 sizeof(PROCESS_JOB_MEMORY_INFO) /* ProcessJobMemoryInformation */,
4212#endif
4213 };
4214 ULONG i, status, ret_len;
4215 BOOL is_current = hproc == GetCurrentProcess();
4216
4217 if (!pNtQueryInformationProcess)
4218 {
4219 win_skip("NtQueryInformationProcess is not available on this platform\n");
4220 return;
4221 }
4222
4223 for (i = 0; i < ARRAY_SIZE(info_size); i++)
4224 {
4225 ret_len = 0;
4226 status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len);
4227 if (status == STATUS_NOT_IMPLEMENTED) continue;
4228 if (status == STATUS_INVALID_INFO_CLASS) continue;
4229 if (status == STATUS_INFO_LENGTH_MISMATCH) continue;
4230
4231 switch (i)
4232 {
4233 case ProcessBasicInformation:
4234 case ProcessQuotaLimits:
4235 case ProcessTimes:
4236 case ProcessPriorityClass:
4237 case ProcessPriorityBoost:
4238 case ProcessLUIDDeviceMapsEnabled:
4239 case ProcessIoPriority:
4240 case ProcessIoCounters:
4241 case ProcessVmCounters:
4242 case ProcessWow64Information:
4243 case ProcessDefaultHardErrorMode:
4244 case ProcessHandleCount:
4245 case ProcessImageFileName:
4246 case ProcessImageInformation:
4247 case ProcessCycleTime:
4248 case ProcessPagePriority:
4249 case ProcessImageFileNameWin32:
4250#ifdef __REACTOS__
4251 ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED || status == STATUS_INVALID_PARAMETER) /* WS03 */, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len);
4252#else
4253 ok(status == STATUS_SUCCESS, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len);
4254#endif
4255 break;
4256
4257 case ProcessAffinityMask:
4258 case ProcessBreakOnTermination:
4259 ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */,
4260 "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len);
4261 break;
4262
4263 case ProcessDebugObjectHandle:
4264 ok(status == STATUS_ACCESS_DENIED || status == STATUS_PORT_NOT_SET,
4265 "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len);
4266 break;
4267 case ProcessCookie:
4268 if (is_current)
4269 ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER /* before win8 */,
4270 "for info %lu got %08lx (ret_len %lu)\n", i, status, ret_len);
4271 else
4272 ok(status == STATUS_INVALID_PARAMETER /* before win8 */ || status == STATUS_ACCESS_DENIED,
4273 "for info %lu got %08lx (ret_len %lu)\n", i, status, ret_len);
4274 break;
4275 case ProcessExecuteFlags:
4276 case ProcessDebugPort:
4277 case ProcessDebugFlags:
4278 if (is_current)
4279 ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER,
4280 "for info %lu, got %08lx (ret_len %lu)\n", i, status, ret_len);
4281 else
4282 todo_wine
4283#ifdef __REACTOS__
4284 ok(status == STATUS_ACCESS_DENIED || broken(status == STATUS_INVALID_PARAMETER) /* WS03 */,
4285#else
4286 ok(status == STATUS_ACCESS_DENIED,
4287#endif
4288 "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len);
4289 break;
4290
4291 default:
4292 if (is_current)
4293 ok(status == STATUS_SUCCESS || status == STATUS_UNSUCCESSFUL || status == STATUS_INVALID_PARAMETER,
4294 "for info %lu, got %08lx (ret_len %lu)\n", i, status, ret_len);
4295 else
4296 ok(status == STATUS_ACCESS_DENIED,
4297 "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len);
4298 break;
4299 }
4300 }
4301}
4302
4303static void test_GetLogicalProcessorInformationEx(void)
4304{
4305 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info;
4306 DWORD len;
4307 BOOL ret;
4308
4309 if (!pGetLogicalProcessorInformationEx)
4310 {
4311 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
4312 return;
4313 }
4314
4315 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, NULL);
4316 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError());
4317
4318 len = 0;
4319 ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len);
4320 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %ld\n", ret, GetLastError());
4321 ok(len > 0, "got %lu\n", len);
4322
4323 len = 0;
4324 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len);
4325 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %ld\n", ret, GetLastError());
4326 ok(len > 0, "got %lu\n", len);
4327
4328 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
4329 ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len);
4330 ok(ret, "got %d, error %ld\n", ret, GetLastError());
4331 ok(info->Size > 0, "got %lu\n", info->Size);
4332 HeapFree(GetProcessHeap(), 0, info);
4333}
4334
4335static void test_GetSystemCpuSetInformation(void)
4336{
4337#ifdef __REACTOS__
4338 skip("Cannot build test_GetSystemCpuSetInformation() until kernelbase is synced.\n");
4339#else
4340 SYSTEM_CPU_SET_INFORMATION *info, *info_nt;
4341 HANDLE process = GetCurrentProcess();
4342 ULONG size, expected_size;
4343 NTSTATUS status;
4344 SYSTEM_INFO si;
4345 BOOL ret;
4346
4347 if (!pGetSystemCpuSetInformation)
4348 {
4349 win_skip("GetSystemCpuSetInformation() is not supported.\n");
4350 return;
4351 }
4352
4353 GetSystemInfo(&si);
4354
4355 expected_size = sizeof(*info) * si.dwNumberOfProcessors;
4356
4357 if (0)
4358 {
4359 /* Crashes on Windows with NULL return length. */
4360 pGetSystemCpuSetInformation(NULL, 0, NULL, process, 0);
4361 }
4362
4363 size = 0xdeadbeef;
4364 SetLastError(0xdeadbeef);
4365 ret = pGetSystemCpuSetInformation(NULL, size, &size, process, 0);
4366 ok(!ret && GetLastError() == ERROR_NOACCESS, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4367 ok(!size, "Got unexpected size %lu.\n", size);
4368
4369 size = 0xdeadbeef;
4370 SetLastError(0xdeadbeef);
4371 ret = pGetSystemCpuSetInformation(NULL, 0, &size, (HANDLE)0xdeadbeef, 0);
4372 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4373 ok(!size, "Got unexpected size %lu.\n", size);
4374
4375 size = 0xdeadbeef;
4376 SetLastError(0xdeadbeef);
4377 ret = pGetSystemCpuSetInformation(NULL, 0, &size, process, 0);
4378 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4379 ok(size == expected_size, "Got unexpected size %lu.\n", size);
4380
4381 info = heap_alloc(size);
4382 info_nt = heap_alloc(size);
4383
4384 status = pNtQuerySystemInformationEx(SystemCpuSetInformation, &process, sizeof(process), info_nt, expected_size, NULL);
4385 ok(!status, "Got unexpected status %#lx.\n", status);
4386
4387 size = 0xdeadbeef;
4388 SetLastError(0xdeadbeef);
4389 ret = pGetSystemCpuSetInformation(info, expected_size, &size, process, 0);
4390 ok(ret && GetLastError() == 0xdeadbeef, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4391 ok(size == expected_size, "Got unexpected size %lu.\n", size);
4392
4393 ok(!memcmp(info, info_nt, expected_size), "Info does not match NtQuerySystemInformationEx().\n");
4394
4395 heap_free(info_nt);
4396 heap_free(info);
4397#endif
4398}
4399
4400static void test_largepages(void)
4401{
4402 SIZE_T size;
4403
4404 if (!pGetLargePageMinimum) {
4405 win_skip("No GetLargePageMinimum support.\n");
4406 return;
4407 }
4408 size = pGetLargePageMinimum();
4409
4410 ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %Id size\n", size);
4411}
4412
4413struct proc_thread_attr
4414{
4415 DWORD_PTR attr;
4416 SIZE_T size;
4417 void *value;
4418};
4419
4420struct _PROC_THREAD_ATTRIBUTE_LIST
4421{
4422 DWORD mask; /* bitmask of items in list */
4423 DWORD size; /* max number of items in list */
4424 DWORD count; /* number of items in list */
4425 DWORD pad;
4426 DWORD_PTR unk;
4427 struct proc_thread_attr attrs[10];
4428};
4429
4430static void test_ProcThreadAttributeList(void)
4431{
4432 BOOL ret;
4433 SIZE_T size, needed;
4434 int i;
4435 struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list;
4436 HANDLE handles[4];
4437
4438 if (!pInitializeProcThreadAttributeList)
4439 {
4440 win_skip("No support for ProcThreadAttributeList\n");
4441 return;
4442 }
4443
4444 for (i = 0; i <= 10; i++)
4445 {
4446 needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[i]);
4447 ret = pInitializeProcThreadAttributeList(NULL, i, 0, &size);
4448 ok(!ret, "got %d\n", ret);
4449 if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */
4450 break;
4451 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %ld\n", GetLastError());
4452 ok(size == needed, "%d: got %Id expect %Id\n", i, size, needed);
4453
4454 memset(&list, 0xcc, sizeof(list));
4455 ret = pInitializeProcThreadAttributeList(&list, i, 0, &size);
4456 ok(ret, "got %d\n", ret);
4457 ok(list.mask == 0, "%d: got %08lx\n", i, list.mask);
4458 ok(list.size == i, "%d: got %08lx\n", i, list.size);
4459 ok(list.count == 0, "%d: got %08lx\n", i, list.count);
4460 ok(list.unk == 0, "%d: got %08Ix\n", i, list.unk);
4461 }
4462
4463 memset(handles, 0, sizeof(handles));
4464 memset(&expect_list, 0xcc, sizeof(expect_list));
4465 expect_list.mask = 0;
4466 expect_list.size = i - 1;
4467 expect_list.count = 0;
4468 expect_list.unk = 0;
4469
4470 ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
4471 ok(!ret, "got %d\n", ret);
4472 ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %ld\n", GetLastError());
4473
4474 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL);
4475 ok(!ret, "got %d\n", ret);
4476 ok(GetLastError() == ERROR_BAD_LENGTH, "got %ld\n", GetLastError());
4477
4478 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL);
4479 ok(!ret, "got %d\n", ret);
4480 ok(GetLastError() == ERROR_BAD_LENGTH, "got %ld\n", GetLastError());
4481
4482 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
4483 ok(ret, "got %d\n", ret);
4484
4485 expect_list.mask |= 1 << ProcThreadAttributeParentProcess;
4486 expect_list.attrs[0].attr = PROC_THREAD_ATTRIBUTE_PARENT_PROCESS;
4487 expect_list.attrs[0].size = sizeof(handles[0]);
4488 expect_list.attrs[0].value = handles;
4489 expect_list.count++;
4490
4491 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
4492 ok(!ret, "got %d\n", ret);
4493 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %ld\n", GetLastError());
4494
4495 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL);
4496 ok(!ret, "got %d\n", ret);
4497 ok(GetLastError() == ERROR_BAD_LENGTH, "got %ld\n", GetLastError());
4498
4499 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
4500 ok(ret, "got %d\n", ret);
4501
4502 expect_list.mask |= 1 << ProcThreadAttributeHandleList;
4503 expect_list.attrs[1].attr = PROC_THREAD_ATTRIBUTE_HANDLE_LIST;
4504 expect_list.attrs[1].size = sizeof(handles);
4505 expect_list.attrs[1].value = handles;
4506 expect_list.count++;
4507
4508 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
4509 ok(!ret, "got %d\n", ret);
4510 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %ld\n", GetLastError());
4511
4512 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
4513 ok(ret || GetLastError() == ERROR_NOT_SUPPORTED, "got %d gle %ld\n", ret, GetLastError());
4514
4515 if (ret)
4516 {
4517 expect_list.mask |= 1 << ProcThreadAttributeIdealProcessor;
4518 expect_list.attrs[2].attr = PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR;
4519 expect_list.attrs[2].size = sizeof(PROCESSOR_NUMBER);
4520 expect_list.attrs[2].value = handles;
4521 expect_list.count++;
4522 }
4523
4524 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, handles, sizeof(handles[0]), NULL, NULL);
4525 ok(ret || broken(GetLastError() == ERROR_NOT_SUPPORTED), "got %d gle %ld\n", ret, GetLastError());
4526
4527 if (ret)
4528 {
4529 unsigned int i = expect_list.count++;
4530 expect_list.mask |= 1 << ProcThreadAttributePseudoConsole;
4531 expect_list.attrs[i].attr = PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE;
4532 expect_list.attrs[i].size = sizeof(HPCON);
4533 expect_list.attrs[i].value = handles;
4534 }
4535
4536 ok(!memcmp(&list, &expect_list, size), "mismatch\n");
4537
4538 pDeleteProcThreadAttributeList(&list);
4539}
4540
4541/* level 0: Main test process
4542 * level 1: Process created by level 0 process without handle inheritance
4543 * level 2: Process created by level 1 process with handle inheritance and level 0
4544 * process parent substitute.
4545 * level 255: Process created by level 1 process during invalid parent handles testing. */
4546static void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
4547{
4548 PROCESS_BASIC_INFORMATION pbi;
4549 char buffer[MAX_PATH + 64];
4550 HANDLE write_pipe = NULL;
4551 PROCESS_INFORMATION info;
4552 SECURITY_ATTRIBUTES sa;
4553 STARTUPINFOEXA si;
4554 DWORD parent_id;
4555 NTSTATUS status;
4556 ULONG pbi_size;
4557 HANDLE parent;
4558 DWORD size;
4559 BOOL ret;
4560
4561 struct
4562 {
4563 HANDLE parent;
4564 DWORD parent_id;
4565 }
4566 parent_data;
4567
4568 if (level == 255)
4569 return;
4570
4571 if (!pInitializeProcThreadAttributeList)
4572 {
4573 win_skip("No support for ProcThreadAttributeList.\n");
4574 return;
4575 }
4576
4577 memset(&sa, 0, sizeof(sa));
4578 sa.nLength = sizeof(sa);
4579 sa.bInheritHandle = TRUE;
4580
4581 if (!level)
4582 {
4583 ret = CreatePipe(&read_pipe, &write_pipe, &sa, 0);
4584 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4585
4586 parent_data.parent = OpenProcess(PROCESS_CREATE_PROCESS | PROCESS_QUERY_INFORMATION, TRUE, GetCurrentProcessId());
4587 parent_data.parent_id = GetCurrentProcessId();
4588 }
4589 else
4590 {
4591 status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &pbi_size);
4592 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
4593 parent_id = pbi.InheritedFromUniqueProcessId;
4594
4595 memset(&parent_data, 0, sizeof(parent_data));
4596 ret = ReadFile(read_pipe, &parent_data, sizeof(parent_data), &size, NULL);
4597 ok((level == 2 && ret) || (level == 1 && !ret && GetLastError() == ERROR_INVALID_HANDLE),
4598 "Got unexpected ret %#x, level %u, GetLastError() %lu.\n",
4599 ret, level, GetLastError());
4600 }
4601
4602 if (level == 2)
4603 {
4604 ok(parent_id == parent_data.parent_id, "Got parent id %lu, parent_data.parent_id %lu.\n",
4605 parent_id, parent_data.parent_id);
4606 return;
4607 }
4608
4609 memset(&si, 0, sizeof(si));
4610 si.StartupInfo.cb = sizeof(si);
4611
4612 if (level)
4613 {
4614 HANDLE handle;
4615 SIZE_T size;
4616
4617 ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size);
4618 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
4619 "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4620
4621 sprintf(buffer, "\"%s\" process parent %u %p", selfname, 255, read_pipe);
4622
4623#if 0
4624 /* Crashes on some Windows installations, otherwise successfully creates process. */
4625 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT,
4626 NULL, NULL, (STARTUPINFOA *)&si, &info);
4627 ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
4628 wait_and_close_child_process(&info);
4629#endif
4630 si.lpAttributeList = heap_alloc(size);
4631 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4632 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4633 handle = OpenProcess(PROCESS_CREATE_PROCESS, TRUE, GetCurrentProcessId());
4634 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4635 &handle, sizeof(handle), NULL, NULL);
4636 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4637 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
4638 NULL, NULL, (STARTUPINFOA *)&si, &info);
4639 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4640 wait_and_close_child_process(&info);
4641 CloseHandle(handle);
4642 pDeleteProcThreadAttributeList(si.lpAttributeList);
4643 heap_free(si.lpAttributeList);
4644
4645 si.lpAttributeList = heap_alloc(size);
4646 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4647 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4648 handle = (HANDLE)0xdeadbeef;
4649 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4650 &handle, sizeof(handle), NULL, NULL);
4651 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4652 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
4653 NULL, NULL, (STARTUPINFOA *)&si, &info);
4654 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n",
4655 ret, GetLastError());
4656 pDeleteProcThreadAttributeList(si.lpAttributeList);
4657 heap_free(si.lpAttributeList);
4658
4659 si.lpAttributeList = heap_alloc(size);
4660 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4661 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4662 handle = NULL;
4663 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4664 &handle, sizeof(handle), NULL, NULL);
4665 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4666 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
4667 NULL, NULL, (STARTUPINFOA *)&si, &info);
4668 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n",
4669 ret, GetLastError());
4670 pDeleteProcThreadAttributeList(si.lpAttributeList);
4671 heap_free(si.lpAttributeList);
4672
4673 si.lpAttributeList = heap_alloc(size);
4674 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4675 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4676 handle = GetCurrentProcess();
4677 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4678 &handle, sizeof(handle), NULL, NULL);
4679 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4680 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
4681 NULL, NULL, (STARTUPINFOA *)&si, &info);
4682 /* Broken on Vista / w7 / w10. */
4683 ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_HANDLE),
4684 "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4685 if (ret)
4686 wait_and_close_child_process(&info);
4687 pDeleteProcThreadAttributeList(si.lpAttributeList);
4688 heap_free(si.lpAttributeList);
4689
4690 si.lpAttributeList = heap_alloc(size);
4691 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4692 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4693
4694 parent = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, parent_id);
4695
4696 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4697 &parent, sizeof(parent), NULL, NULL);
4698 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4699 }
4700
4701 sprintf(buffer, "\"%s\" process parent %u %p", selfname, level + 1, read_pipe);
4702 ret = CreateProcessA(NULL, buffer, NULL, NULL, level == 1, level == 1 ? EXTENDED_STARTUPINFO_PRESENT : 0,
4703 NULL, NULL, (STARTUPINFOA *)&si, &info);
4704 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4705
4706 if (level)
4707 {
4708 pDeleteProcThreadAttributeList(si.lpAttributeList);
4709 heap_free(si.lpAttributeList);
4710 CloseHandle(parent);
4711 }
4712 else
4713 {
4714 ret = WriteFile(write_pipe, &parent_data, sizeof(parent_data), &size, NULL);
4715 }
4716
4717 wait_and_close_child_process(&info);
4718
4719 if (!level)
4720 {
4721 CloseHandle(read_pipe);
4722 CloseHandle(write_pipe);
4723 CloseHandle(parent_data.parent);
4724 }
4725}
4726
4727static void test_handle_list_attribute(BOOL child, HANDLE handle1, HANDLE handle2)
4728{
4729 char buffer[MAX_PATH + 64];
4730 HANDLE pipe[2];
4731 PROCESS_INFORMATION info;
4732 STARTUPINFOEXA si;
4733 SIZE_T size;
4734 BOOL ret;
4735 SECURITY_ATTRIBUTES sa;
4736
4737 if (child)
4738 {
4739 char name1[256], name2[256];
4740 DWORD flags;
4741
4742 flags = 0;
4743 ret = GetHandleInformation(handle1, &flags);
4744 ok(ret, "Failed to get handle info, error %ld.\n", GetLastError());
4745 ok(flags == HANDLE_FLAG_INHERIT, "Unexpected flags %#lx.\n", flags);
4746#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
4747 ret = GetFileInformationByHandleEx(handle1, FileNameInfo, name1, sizeof(name1));
4748 ok(ret, "Failed to get pipe name, error %ld\n", GetLastError());
4749#endif
4750 CloseHandle(handle1);
4751 flags = 0;
4752 ret = GetHandleInformation(handle2, &flags);
4753 if (ret)
4754 {
4755 ok(!(flags & HANDLE_FLAG_INHERIT), "Parent's handle shouldn't have been inherited\n");
4756#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
4757 ret = GetFileInformationByHandleEx(handle2, FileNameInfo, name2, sizeof(name2));
4758 ok(!ret || strcmp(name1, name2), "Parent's handle shouldn't have been inherited\n");
4759#endif
4760 }
4761 else
4762 ok(GetLastError() == ERROR_INVALID_HANDLE, "Unexpected return value, error %ld.\n", GetLastError());
4763
4764 return;
4765 }
4766
4767#ifdef __REACTOS__
4768 if (GetNTVersion() < _WIN32_WINNT_VISTA) {
4769 skip("test_handle_list_attribute() crashes on WS03.\n");
4770 return;
4771 }
4772#endif
4773 ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size);
4774 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
4775 "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4776
4777 memset(&si, 0, sizeof(si));
4778 si.StartupInfo.cb = sizeof(si);
4779 si.lpAttributeList = heap_alloc(size);
4780 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4781 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4782
4783 memset(&sa, 0, sizeof(sa));
4784 sa.nLength = sizeof(sa);
4785 sa.bInheritHandle = TRUE;
4786
4787 ret = CreatePipe(&pipe[0], &pipe[1], &sa, 1024);
4788 ok(ret, "Failed to create a pipe.\n");
4789
4790 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &pipe[0],
4791 sizeof(pipe[0]), NULL, NULL);
4792 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4793
4794 sprintf(buffer, "\"%s\" process handlelist %p %p", selfname, pipe[0], pipe[1]);
4795 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
4796 (STARTUPINFOA *)&si, &info);
4797 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4798
4799 wait_and_close_child_process(&info);
4800
4801 CloseHandle(pipe[0]);
4802 CloseHandle(pipe[1]);
4803}
4804
4805static void test_dead_process(void)
4806{
4807 DWORD_PTR data[256];
4808 PROCESS_BASIC_INFORMATION basic;
4809 SYSTEM_PROCESS_INFORMATION *spi;
4810 SECTION_IMAGE_INFORMATION image;
4811 PROCESS_INFORMATION pi;
4812 PROCESS_PRIORITY_CLASS *prio = (PROCESS_PRIORITY_CLASS *)data;
4813 BYTE *buffer = NULL;
4814 BOOL found;
4815 ULONG size = 0;
4816 DWORD offset = 0;
4817 NTSTATUS status;
4818
4819#ifdef __REACTOS__
4820 if (GetNTVersion() < _WIN32_WINNT_VISTA) {
4821 skip("test_dead_process() crashes on WS03.\n");
4822 return;
4823 }
4824#endif
4825 create_process("exit", &pi);
4826 wait_child_process(pi.hProcess);
4827 Sleep(100);
4828
4829 memset( data, 0, sizeof(data) );
4830 status = NtQueryInformationProcess( pi.hProcess, ProcessImageFileName, data, sizeof(data), NULL);
4831 ok( !status, "ProcessImageFileName failed %lx\n", status );
4832 ok( ((UNICODE_STRING *)data)->Length, "ProcessImageFileName not set\n" );
4833 ok( ((UNICODE_STRING *)data)->Buffer[0] == '\\', "ProcessImageFileName not set\n" );
4834
4835 memset( prio, 0xcc, sizeof(*prio) );
4836 status = NtQueryInformationProcess( pi.hProcess, ProcessPriorityClass, prio, sizeof(*prio), NULL);
4837 ok( !status, "ProcessPriorityClass failed %lx\n", status );
4838 ok( prio->PriorityClass != 0xcc, "ProcessPriorityClass not set\n" );
4839
4840 memset( &basic, 0xcc, sizeof(basic) );
4841 status = NtQueryInformationProcess( pi.hProcess, ProcessBasicInformation, &basic, sizeof(basic), NULL);
4842 ok( !status, "ProcessBasicInformation failed %lx\n", status );
4843 ok( basic.ExitStatus == 0, "ProcessBasicInformation info modified\n" );
4844
4845 memset( &image, 0xcc, sizeof(image) );
4846 status = NtQueryInformationProcess( pi.hProcess, ProcessImageInformation, &image, sizeof(image), NULL);
4847 ok( status == STATUS_PROCESS_IS_TERMINATING, "ProcessImageInformation wrong error %lx\n", status );
4848 ok( image.Machine == 0xcccc, "ProcessImageInformation info modified\n" );
4849
4850 while ((status = NtQuerySystemInformation(SystemProcessInformation, buffer, size, &size)) == STATUS_INFO_LENGTH_MISMATCH)
4851 {
4852 free(buffer);
4853 buffer = malloc(size);
4854 }
4855 ok(status == STATUS_SUCCESS, "got %#lx\n", status);
4856 found = FALSE;
4857 do
4858 {
4859 spi = (SYSTEM_PROCESS_INFORMATION *)(buffer + offset);
4860 if (spi->UniqueProcessId == ULongToHandle(pi.dwProcessId))
4861 {
4862 found = TRUE;
4863 break;
4864 }
4865 offset += spi->NextEntryOffset;
4866 } while (spi->NextEntryOffset);
4867 ok( !found, "process still enumerated\n" );
4868 CloseHandle(pi.hProcess);
4869 CloseHandle(pi.hThread);
4870}
4871
4872static void test_nested_jobs_child(unsigned int index)
4873{
4874 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
4875 HANDLE job, job_parent, job_other, port;
4876 PROCESS_INFORMATION pi;
4877 OVERLAPPED *overlapped;
4878 char job_name[32];
4879 ULONG_PTR value;
4880 DWORD dead_pid;
4881 BOOL ret, out;
4882 DWORD key;
4883
4884 sprintf(job_name, "test_nested_jobs_%u", index);
4885 job = pOpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_SET_ATTRIBUTES | JOB_OBJECT_QUERY
4886 | JOB_OBJECT_TERMINATE, FALSE, job_name);
4887 ok(!!job, "OpenJobObjectA error %lu\n", GetLastError());
4888
4889 sprintf(job_name, "test_nested_jobs_%u", !index);
4890 job_other = pOpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_SET_ATTRIBUTES | JOB_OBJECT_QUERY
4891 | JOB_OBJECT_TERMINATE, FALSE, job_name);
4892 ok(!!job_other, "OpenJobObjectA error %lu\n", GetLastError());
4893
4894 job_parent = pCreateJobObjectW(NULL, NULL);
4895 ok(!!job_parent, "CreateJobObjectA error %lu\n", GetLastError());
4896
4897 ret = pAssignProcessToJobObject(job_parent, GetCurrentProcess());
4898 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
4899
4900 create_process("wait", &pi);
4901
4902 ret = pAssignProcessToJobObject(job_parent, pi.hProcess);
4903 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED) /* Supported since Windows 8. */,
4904 "AssignProcessToJobObject error %lu\n", GetLastError());
4905 if (!ret)
4906 {
4907 win_skip("Nested jobs are not supported.\n");
4908 goto done;
4909 }
4910 ret = pAssignProcessToJobObject(job, pi.hProcess);
4911 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
4912
4913 out = FALSE;
4914 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
4915 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4916 ok(out, "IsProcessInJob returned out=%u\n", out);
4917
4918 out = FALSE;
4919 ret = pIsProcessInJob(pi.hProcess, job, &out);
4920 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4921 ok(out, "IsProcessInJob returned out=%u\n", out);
4922
4923 out = TRUE;
4924 ret = pIsProcessInJob(GetCurrentProcess(), job, &out);
4925 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4926 ok(!out, "IsProcessInJob returned out=%u\n", out);
4927
4928 out = FALSE;
4929 ret = pIsProcessInJob(pi.hProcess, job, &out);
4930 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4931 ok(out, "IsProcessInJob returned out=%u\n", out);
4932
4933 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
4934 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
4935
4936 TerminateProcess(pi.hProcess, 0);
4937 wait_child_process(pi.hProcess);
4938 CloseHandle(pi.hProcess);
4939 CloseHandle(pi.hThread);
4940
4941 dead_pid = pi.dwProcessId;
4942
4943 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
4944 ok(!!port, "CreateIoCompletionPort error %lu\n", GetLastError());
4945
4946 port_info.CompletionPort = port;
4947 port_info.CompletionKey = job;
4948 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
4949 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
4950 port_info.CompletionKey = job_parent;
4951 ret = pSetInformationJobObject(job_parent, JobObjectAssociateCompletionPortInformation,
4952 &port_info, sizeof(port_info));
4953 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
4954
4955 create_process("wait", &pi);
4956 out = FALSE;
4957 ret = pIsProcessInJob(pi.hProcess, job, &out);
4958 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4959 ok(out, "IsProcessInJob returned out=%u\n", out);
4960
4961 out = FALSE;
4962 ret = pIsProcessInJob(pi.hProcess, job_parent, &out);
4963 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4964 ok(out, "IsProcessInJob returned out=%u\n", out);
4965
4966 /* The first already dead child process still shows up randomly. */
4967 do
4968 {
4969 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
4970 } while (ret && (ULONG_PTR)overlapped == dead_pid);
4971
4972 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4973 ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %lx\n", key);
4974 ok((HANDLE)value == job, "unexpected value %p\n", (void *)value);
4975 ok((ULONG_PTR)overlapped == GetCurrentProcessId(), "unexpected pid %#lx\n", (DWORD)(DWORD_PTR)overlapped);
4976
4977 do
4978 {
4979 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
4980 } while (ret && (ULONG_PTR)overlapped == dead_pid);
4981
4982 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4983 ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %lx\n", key);
4984 ok((HANDLE)value == job_parent, "unexpected value %p\n", (void *)value);
4985 ok((ULONG_PTR)overlapped == GetCurrentProcessId(), "unexpected pid %#lx\n", (DWORD)(DWORD_PTR)overlapped);
4986
4987 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
4988 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job_parent, pi.dwProcessId, 0);
4989
4990 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
4991 ok(!ret, "GetQueuedCompletionStatus succeeded.\n");
4992
4993 if (index)
4994 {
4995 ret = pAssignProcessToJobObject(job_other, GetCurrentProcess());
4996 ok(!ret, "AssignProcessToJobObject succeeded\n");
4997 ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %lu.\n", GetLastError());
4998 }
4999
5000 CloseHandle(port);
5001
5002done:
5003 TerminateProcess(pi.hProcess, 0);
5004 wait_child_process(pi.hProcess);
5005
5006 CloseHandle(pi.hProcess);
5007 CloseHandle(pi.hThread);
5008 CloseHandle(job_parent);
5009 CloseHandle(job);
5010 CloseHandle(job_other);
5011}
5012
5013static void test_nested_jobs(void)
5014{
5015 BOOL ret, already_in_job = TRUE, create_succeeded = FALSE;
5016 PROCESS_INFORMATION info[2];
5017 char buffer[MAX_PATH + 26];
5018 STARTUPINFOA si = {0};
5019 HANDLE job1, job2;
5020 unsigned int i;
5021
5022 if (!pIsProcessInJob)
5023 {
5024 win_skip("IsProcessInJob not available.\n");
5025 return;
5026 }
5027
5028 job1 = pCreateJobObjectW(NULL, NULL);
5029 ok(!!job1, "CreateJobObjectW failed, error %lu.\n", GetLastError());
5030 job2 = pCreateJobObjectW(NULL, NULL);
5031 ok(!!job2, "CreateJobObjectW failed, error %lu.\n", GetLastError());
5032
5033 create_succeeded = TRUE;
5034 sprintf(buffer, "\"%s\" process wait", selfname);
5035 for (i = 0; i < 2; ++i)
5036 {
5037 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &info[i]);
5038 if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
5039 {
5040 create_succeeded = FALSE;
5041 break;
5042 }
5043 ok(ret, "CreateProcessA error %lu\n", GetLastError());
5044 }
5045
5046 if (create_succeeded)
5047 {
5048 ret = pIsProcessInJob(info[0].hProcess, NULL, &already_in_job);
5049 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5050
5051 if (!already_in_job)
5052 {
5053 ret = pAssignProcessToJobObject(job2, info[1].hProcess);
5054 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
5055
5056 ret = pAssignProcessToJobObject(job1, info[0].hProcess);
5057 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
5058
5059 ret = pAssignProcessToJobObject(job2, info[0].hProcess);
5060 ok(!ret, "AssignProcessToJobObject succeeded\n");
5061 ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %lu.\n", GetLastError());
5062
5063 TerminateProcess(info[1].hProcess, 0);
5064 wait_child_process(info[1].hProcess);
5065 CloseHandle(info[1].hProcess);
5066 CloseHandle(info[1].hThread);
5067
5068 ret = pAssignProcessToJobObject(job2, info[0].hProcess);
5069 ok(!ret, "AssignProcessToJobObject succeeded\n");
5070 ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %lu.\n", GetLastError());
5071 }
5072
5073 TerminateProcess(info[0].hProcess, 0);
5074 wait_child_process(info[0].hProcess);
5075 CloseHandle(info[0].hProcess);
5076 CloseHandle(info[0].hThread);
5077 }
5078
5079 if (already_in_job)
5080 {
5081 win_skip("Test process is already in job, can't test parenting non-empty job.\n");
5082 }
5083
5084 CloseHandle(job1);
5085 CloseHandle(job2);
5086
5087 job1 = pCreateJobObjectW(NULL, L"test_nested_jobs_0");
5088 ok(!!job1, "CreateJobObjectW failed, error %lu.\n", GetLastError());
5089 job2 = pCreateJobObjectW(NULL, L"test_nested_jobs_1");
5090 ok(!!job2, "CreateJobObjectW failed, error %lu.\n", GetLastError());
5091
5092 sprintf(buffer, "\"%s\" process nested_jobs 0", selfname);
5093 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info[0]),
5094 "CreateProcess failed\n");
5095 wait_child_process(info[0].hProcess);
5096 sprintf(buffer, "\"%s\" process nested_jobs 1", selfname);
5097 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info[1]),
5098 "CreateProcess failed\n");
5099 wait_child_process(info[1].hProcess);
5100 for (i = 0; i < 2; ++i)
5101 {
5102 CloseHandle(info[i].hProcess);
5103 CloseHandle(info[i].hThread);
5104 }
5105
5106 CloseHandle(job1);
5107 CloseHandle(job2);
5108}
5109
5110static void test_job_list_attribute(HANDLE parent_job)
5111{
5112 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION job_info;
5113 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
5114 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
5115 PPROC_THREAD_ATTRIBUTE_LIST attrs;
5116 char buffer[MAX_PATH + 19];
5117 PROCESS_INFORMATION pi;
5118 OVERLAPPED *overlapped;
5119 HANDLE jobs[2], port;
5120 STARTUPINFOEXA si;
5121 ULONG_PTR value;
5122 BOOL ret, out;
5123 HANDLE tmp;
5124 SIZE_T size;
5125 DWORD key;
5126
5127 if (!pInitializeProcThreadAttributeList)
5128 {
5129 win_skip("No support for ProcThreadAttributeList\n");
5130 return;
5131 }
5132
5133 ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size);
5134 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
5135 "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5136 attrs = heap_alloc(size);
5137
5138
5139 jobs[0] = (HANDLE)0xdeadbeef;
5140 jobs[1] = NULL;
5141
5142 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5143 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5144 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
5145 sizeof(*jobs), NULL, NULL);
5146 if (!ret && GetLastError() == ERROR_NOT_SUPPORTED)
5147 {
5148 /* Supported since Win10. */
5149 win_skip("PROC_THREAD_ATTRIBUTE_JOB_LIST is not supported.\n");
5150 pDeleteProcThreadAttributeList(attrs);
5151 heap_free(attrs);
5152 return;
5153 }
5154 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5155
5156 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5157 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5158 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
5159 3, NULL, NULL);
5160 ok(!ret && GetLastError() == ERROR_BAD_LENGTH, "Got unexpected ret %#x, GetLastError() %lu.\n",
5161 ret, GetLastError());
5162
5163 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5164 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5165 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
5166 sizeof(*jobs) * 2, NULL, NULL);
5167 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5168
5169 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5170 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5171 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
5172 sizeof(*jobs), NULL, NULL);
5173
5174 memset(&si, 0, sizeof(si));
5175 si.StartupInfo.cb = sizeof(si);
5176 si.lpAttributeList = attrs;
5177 sprintf(buffer, "\"%s\" process wait", selfname);
5178
5179 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
5180 (STARTUPINFOA *)&si, &pi);
5181 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n",
5182 ret, GetLastError());
5183
5184 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5185 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5186 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1,
5187 sizeof(*jobs), NULL, NULL);
5188 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
5189 (STARTUPINFOA *)&si, &pi);
5190 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n",
5191 ret, GetLastError());
5192
5193 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5194 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5195 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &parent_job,
5196 sizeof(parent_job), NULL, NULL);
5197 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
5198 (STARTUPINFOA *)&si, &pi);
5199 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5200
5201 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
5202 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5203 ok(out, "IsProcessInJob returned out=%u\n", out);
5204
5205 TerminateProcess(pi.hProcess, 0);
5206 wait_and_close_child_process(&pi);
5207
5208 jobs[0] = pCreateJobObjectW(NULL, NULL);
5209 ok(!!jobs[0], "CreateJobObjectA error %lu\n", GetLastError());
5210 jobs[1] = pCreateJobObjectW(NULL, NULL);
5211 ok(!!jobs[1], "CreateJobObjectA error %lu\n", GetLastError());
5212
5213 /* Breakaway works for the inherited job only. */
5214 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
5215 ret = pSetInformationJobObject(parent_job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
5216 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
5217 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK
5218 | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
5219 ret = pSetInformationJobObject(jobs[1], JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
5220 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
5221
5222 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5223 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5224 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1,
5225 sizeof(*jobs), NULL, NULL);
5226 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT
5227 | CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, (STARTUPINFOA *)&si, &pi);
5228 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5229
5230 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
5231 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5232 ok(!out, "IsProcessInJob returned out=%u\n", out);
5233
5234 ret = pIsProcessInJob(pi.hProcess, jobs[1], &out);
5235 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5236 ok(out, "IsProcessInJob returned out=%u\n", out);
5237
5238 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
5239 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5240 ok(!out, "IsProcessInJob returned out=%u\n", out);
5241
5242 TerminateProcess(pi.hProcess, 0);
5243 wait_and_close_child_process(&pi);
5244
5245 CloseHandle(jobs[1]);
5246 jobs[1] = pCreateJobObjectW(NULL, NULL);
5247 ok(!!jobs[1], "CreateJobObjectA error %lu\n", GetLastError());
5248
5249 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5250 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5251 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1,
5252 sizeof(*jobs), NULL, NULL);
5253 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT,
5254 NULL, NULL, (STARTUPINFOA *)&si, &pi);
5255 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5256
5257 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
5258 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5259 ok(out, "IsProcessInJob returned out=%u\n", out);
5260
5261 ret = pIsProcessInJob(pi.hProcess, jobs[1], &out);
5262 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5263 ok(out, "IsProcessInJob returned out=%u\n", out);
5264
5265 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
5266 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5267 ok(!out, "IsProcessInJob returned out=%u\n", out);
5268
5269 TerminateProcess(pi.hProcess, 0);
5270 wait_and_close_child_process(&pi);
5271
5272 ret = pQueryInformationJobObject(jobs[0], JobObjectBasicAccountingInformation, &job_info,
5273 sizeof(job_info), NULL);
5274 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
5275 ok(!job_info.TotalProcesses, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses);
5276 ok(!job_info.ActiveProcesses, "Got unexpected ActiveProcesses %lu.\n", job_info.ActiveProcesses);
5277
5278 ret = pQueryInformationJobObject(jobs[1], JobObjectBasicAccountingInformation, &job_info,
5279 sizeof(job_info), NULL);
5280 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
5281 ok(job_info.TotalProcesses == 1, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses);
5282 ok(!job_info.ActiveProcesses || job_info.ActiveProcesses == 1, "Got unexpected ActiveProcesses %lu.\n",
5283 job_info.ActiveProcesses);
5284
5285 /* Fails due to the second job already has the parent other than the first job in the list. */
5286 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5287 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5288 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
5289 2 * sizeof(*jobs), NULL, NULL);
5290
5291 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
5292 ok(!!port, "CreateIoCompletionPort error %lu\n", GetLastError());
5293
5294 port_info.CompletionPort = port;
5295 port_info.CompletionKey = jobs[0];
5296 ret = pSetInformationJobObject(jobs[0], JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
5297 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
5298
5299 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
5300 ok(!ret, "GetQueuedCompletionStatus succeeded.\n");
5301
5302 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
5303 (STARTUPINFOA *)&si, &pi);
5304 ok(!ret && GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected ret %#x, GetLastError() %lu.\n",
5305 ret, GetLastError());
5306
5307 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 100);
5308 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
5309 ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %lx\n", key);
5310 ok((HANDLE)value == jobs[0], "unexpected value %p\n", (void *)value);
5311 ok(!!overlapped, "Got zero pid.\n");
5312
5313 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 100);
5314 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
5315 ok(key == JOB_OBJECT_MSG_EXIT_PROCESS, "unexpected key %lx\n", key);
5316 ok((HANDLE)value == jobs[0], "unexpected value %p\n", (void *)value);
5317 ok(!!overlapped, "Got zero pid.\n");
5318
5319 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 100);
5320 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
5321 ok(key == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, "unexpected key %lx\n", key);
5322 ok((HANDLE)value == jobs[0], "unexpected value %p\n", (void *)value);
5323 ok(!overlapped, "Got unexpected overlapped %p.\n", overlapped);
5324
5325 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
5326 ok(!ret, "GetQueuedCompletionStatus succeeded.\n");
5327
5328 CloseHandle(port);
5329
5330 /* The first job got updated even though the process creation failed. */
5331 ret = pQueryInformationJobObject(jobs[0], JobObjectBasicAccountingInformation, &job_info,
5332 sizeof(job_info), NULL);
5333 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
5334 ok(job_info.TotalProcesses == 1, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses);
5335 ok(!job_info.ActiveProcesses, "Got unexpected ActiveProcesses %lu.\n", job_info.ActiveProcesses);
5336
5337 ret = pQueryInformationJobObject(jobs[1], JobObjectBasicAccountingInformation, &job_info,
5338 sizeof(job_info), NULL);
5339 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
5340 ok(job_info.TotalProcesses == 1, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses);
5341 ok(!job_info.ActiveProcesses, "Got unexpected ActiveProcesses %lu.\n", job_info.ActiveProcesses);
5342
5343 /* Check that the first job actually got the job_parent as parent. */
5344 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5345 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5346 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
5347 sizeof(*jobs), NULL, NULL);
5348 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT
5349 | CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, (STARTUPINFOA *)&si, &pi);
5350 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5351
5352 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
5353 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5354 ok(out, "IsProcessInJob returned out=%u\n", out);
5355
5356 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
5357 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5358 ok(out, "IsProcessInJob returned out=%u\n", out);
5359
5360 TerminateProcess(pi.hProcess, 0);
5361 wait_and_close_child_process(&pi);
5362
5363 tmp = jobs[0];
5364 jobs[0] = jobs[1];
5365 jobs[1] = tmp;
5366
5367 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5368 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5369 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
5370 2 * sizeof(*jobs), NULL, NULL);
5371 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
5372 (STARTUPINFOA *)&si, &pi);
5373 ok(!ret && GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected ret %#x, GetLastError() %lu.\n",
5374 ret, GetLastError());
5375
5376 CloseHandle(jobs[0]);
5377 CloseHandle(jobs[1]);
5378
5379 jobs[0] = pCreateJobObjectW(NULL, NULL);
5380 ok(!!jobs[0], "CreateJobObjectA error %lu\n", GetLastError());
5381 jobs[1] = pCreateJobObjectW(NULL, NULL);
5382 ok(!!jobs[1], "CreateJobObjectA error %lu\n", GetLastError());
5383
5384 /* Create the job chain successfully and check the job chain. */
5385 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5386 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5387 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
5388 2 * sizeof(*jobs), NULL, NULL);
5389 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT,
5390 NULL, NULL, (STARTUPINFOA *)&si, &pi);
5391 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5392
5393 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
5394 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5395 ok(out, "IsProcessInJob returned out=%u\n", out);
5396
5397 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
5398 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5399 ok(out, "IsProcessInJob returned out=%u\n", out);
5400
5401 ret = pIsProcessInJob(pi.hProcess, jobs[1], &out);
5402 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5403 ok(out, "IsProcessInJob returned out=%u\n", out);
5404
5405 TerminateProcess(pi.hProcess, 0);
5406 wait_and_close_child_process(&pi);
5407
5408 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
5409 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5410 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1,
5411 sizeof(*jobs), NULL, NULL);
5412 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT
5413 | CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, (STARTUPINFOA *)&si, &pi);
5414 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
5415
5416 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
5417 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5418 ok(out, "IsProcessInJob returned out=%u\n", out);
5419
5420 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
5421 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5422 ok(out, "IsProcessInJob returned out=%u\n", out);
5423
5424 ret = pIsProcessInJob(pi.hProcess, jobs[1], &out);
5425 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
5426 ok(out, "IsProcessInJob returned out=%u\n", out);
5427
5428 TerminateProcess(pi.hProcess, 0);
5429 wait_and_close_child_process(&pi);
5430
5431 CloseHandle(jobs[0]);
5432 CloseHandle(jobs[1]);
5433
5434 pDeleteProcThreadAttributeList(attrs);
5435 heap_free(attrs);
5436
5437 limit_info.BasicLimitInformation.LimitFlags = 0;
5438 ret = pSetInformationJobObject(parent_job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
5439 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
5440}
5441
5442static void test_services_exe(void)
5443{
5444 NTSTATUS status;
5445 ULONG size, offset, try;
5446 char *buf;
5447 SYSTEM_PROCESS_INFORMATION *spi;
5448 ULONG services_pid = 0, services_session_id = ~0;
5449
5450 /* Check that passing a zero size returns a size suitable for the next call,
5451 * taking into account that in rare cases processes may start between the
5452 * two NtQuerySystemInformation() calls. So this may require a few tries.
5453 */
5454 for (try = 0; try < 3; try++)
5455 {
5456 status = NtQuerySystemInformation(SystemProcessInformation, NULL, 0, &size);
5457 ok(status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx\n", status);
5458
5459 buf = malloc(size);
5460 status = NtQuerySystemInformation(SystemProcessInformation, buf, size, &size);
5461 if (status != STATUS_INFO_LENGTH_MISMATCH) break;
5462 free(buf);
5463 }
5464 ok(status == STATUS_SUCCESS, "got %#lx\n", status);
5465
5466 spi = (SYSTEM_PROCESS_INFORMATION *)buf;
5467 offset = 0;
5468
5469 do
5470 {
5471 spi = (SYSTEM_PROCESS_INFORMATION *)(buf + offset);
5472 if (!wcsnicmp(spi->ProcessName.Buffer, L"services.exe", spi->ProcessName.Length/sizeof(WCHAR)))
5473 {
5474 services_pid = HandleToUlong(spi->UniqueProcessId);
5475 services_session_id = spi->SessionId;
5476 }
5477 offset += spi->NextEntryOffset;
5478 } while (spi->NextEntryOffset != 0);
5479
5480 ok(services_pid != 0, "services.exe not found\n");
5481 todo_wine
5482 ok(services_session_id == 0, "got services.exe SessionId %lu\n", services_session_id);
5483}
5484
5485static void test_startupinfo( void )
5486{
5487 STARTUPINFOA startup_beforeA, startup_afterA;
5488 STARTUPINFOW startup_beforeW, startup_afterW;
5489 RTL_USER_PROCESS_PARAMETERS *params;
5490
5491 params = RtlGetCurrentPeb()->ProcessParameters;
5492
5493 startup_beforeA.hStdInput = (HANDLE)0x56780000;
5494 GetStartupInfoA(&startup_beforeA);
5495
5496 startup_beforeW.hStdInput = (HANDLE)0x12340000;
5497 GetStartupInfoW(&startup_beforeW);
5498
5499 /* change a couple of fields in PEB */
5500 params->dwX = ~params->dwX;
5501 params->hStdInput = (HANDLE)~(DWORD_PTR)params->hStdInput;
5502
5503 startup_afterA.hStdInput = (HANDLE)0x87650000;
5504 GetStartupInfoA(&startup_afterA);
5505
5506 /* wharf... ansi version is cached... */
5507 ok(startup_beforeA.dwX == startup_afterA.dwX, "Unexpected field value\n");
5508 ok(startup_beforeA.dwFlags == startup_afterA.dwFlags, "Unexpected field value\n");
5509 ok(startup_beforeA.hStdInput == startup_afterA.hStdInput, "Unexpected field value\n");
5510
5511 if (startup_beforeW.dwFlags & STARTF_USESTDHANDLES)
5512 {
5513 ok(startup_beforeA.hStdInput != NULL && startup_beforeA.hStdInput != INVALID_HANDLE_VALUE,
5514 "Unexpected field value\n");
5515 ok(startup_afterA.hStdInput != NULL && startup_afterA.hStdInput != INVALID_HANDLE_VALUE,
5516 "Unexpected field value\n");
5517 }
5518 else
5519 {
5520 ok(startup_beforeA.hStdInput == INVALID_HANDLE_VALUE, "Unexpected field value %p\n", startup_beforeA.hStdInput);
5521 ok(startup_afterA.hStdInput == INVALID_HANDLE_VALUE, "Unexpected field value %p\n", startup_afterA.hStdInput);
5522 }
5523
5524 /* ... while unicode is not */
5525 startup_afterW.hStdInput = (HANDLE)0x43210000;
5526 GetStartupInfoW(&startup_afterW);
5527
5528 ok(~startup_beforeW.dwX == startup_afterW.dwX, "Unexpected field value\n");
5529 if (startup_beforeW.dwFlags & STARTF_USESTDHANDLES)
5530 {
5531 ok(params->hStdInput == startup_afterW.hStdInput, "Unexpected field value\n");
5532 ok((HANDLE)~(DWORD_PTR)startup_beforeW.hStdInput == startup_afterW.hStdInput, "Unexpected field value\n");
5533 }
5534 else
5535 {
5536 ok(startup_beforeW.hStdInput == (HANDLE)0x12340000, "Unexpected field value\n");
5537 ok(startup_afterW.hStdInput == (HANDLE)0x43210000, "Unexpected field value\n");
5538 }
5539
5540 /* check impact of STARTF_USESTDHANDLES bit */
5541 params->dwFlags ^= STARTF_USESTDHANDLES;
5542
5543 startup_afterW.hStdInput = (HANDLE)0x43210000;
5544 GetStartupInfoW(&startup_afterW);
5545
5546 ok((startup_beforeW.dwFlags ^ STARTF_USESTDHANDLES) == startup_afterW.dwFlags, "Unexpected field value\n");
5547 if (startup_afterW.dwFlags & STARTF_USESTDHANDLES)
5548 {
5549 ok(params->hStdInput == startup_afterW.hStdInput, "Unexpected field value\n");
5550 ok(startup_afterW.hStdInput != (HANDLE)0x43210000, "Unexpected field value\n");
5551 }
5552 else
5553 {
5554 ok(startup_afterW.hStdInput == (HANDLE)0x43210000, "Unexpected field value\n");
5555 }
5556
5557 /* FIXME add more tests to check whether the dwFlags controls the returned
5558 * values (as done for STARTF_USESTDHANDLES) in unicode case.
5559 */
5560
5561 /* reset the modified fields in PEB */
5562 params->dwX = ~params->dwX;
5563 params->hStdInput = (HANDLE)~(DWORD_PTR)params->hStdInput;
5564 params->dwFlags ^= STARTF_USESTDHANDLES;
5565}
5566
5567static void test_GetProcessInformation(void)
5568{
5569 SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION machines[8];
5570 PROCESS_MACHINE_INFORMATION mi;
5571 NTSTATUS status;
5572 HANDLE process;
5573 unsigned int i;
5574 BOOL ret;
5575
5576 if (!pGetProcessInformation)
5577 {
5578 win_skip("GetProcessInformation() is not available.\n");
5579 return;
5580 }
5581
5582 SetLastError(0xdeadbeef);
5583 ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, NULL, 0);
5584 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
5585 {
5586 win_skip("GetProcessInformation(ProcessMachineTypeInfo) is not supported.\n"); /* < win11 */
5587 return;
5588 }
5589 ok(!ret, "Unexpected return value %d.\n", ret);
5590 ok(GetLastError() == ERROR_BAD_LENGTH, "Unexpected error %ld.\n", GetLastError());
5591 SetLastError(0xdeadbeef);
5592 ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, &mi, 0);
5593 ok(!ret, "Unexpected return value %d.\n", ret);
5594 ok(GetLastError() == ERROR_BAD_LENGTH, "Unexpected error %ld.\n", GetLastError());
5595 SetLastError(0xdeadbeef);
5596 ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, &mi, sizeof(mi) - 1);
5597 ok(!ret, "Unexpected return value %d.\n", ret);
5598 ok(GetLastError() == ERROR_BAD_LENGTH, "Unexpected error %ld.\n", GetLastError());
5599 SetLastError(0xdeadbeef);
5600 ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, &mi, sizeof(mi) + 1);
5601 ok(!ret, "Unexpected return value %d.\n", ret);
5602 ok(GetLastError() == ERROR_BAD_LENGTH, "Unexpected error %ld.\n", GetLastError());
5603
5604 ret = pGetProcessInformation(GetCurrentProcess(), ProcessMachineTypeInfo, &mi, sizeof(mi));
5605 ok(ret, "Unexpected return value %d.\n", ret);
5606
5607#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x601
5608 process = GetCurrentProcess();
5609 status = NtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
5610 machines, sizeof(machines), NULL );
5611 ok(!status, "Failed to get architectures information.\n");
5612 for (i = 0; machines[i].Machine; i++)
5613 {
5614 if (machines[i].Process)
5615 {
5616 ok(mi.ProcessMachine == machines[i].Machine, "Unexpected process machine %#x.\n", mi.ProcessMachine);
5617 ok(!!(mi.MachineAttributes & UserEnabled) == machines[i].UserMode, "Unexpected attributes %#x.\n",
5618 mi.MachineAttributes);
5619 ok(!!(mi.MachineAttributes & KernelEnabled) == machines[i].KernelMode, "Unexpected attributes %#x.\n",
5620 mi.MachineAttributes);
5621 ok(!!(mi.MachineAttributes & Wow64Container) == machines[i].WoW64Container, "Unexpected attributes %#x.\n",
5622 mi.MachineAttributes);
5623 ok(!(mi.MachineAttributes & ~(UserEnabled | KernelEnabled | Wow64Container)), "Unexpected attributes %#x.\n",
5624 mi.MachineAttributes);
5625 break;
5626 }
5627 }
5628#endif
5629}
5630
5631START_TEST(process)
5632{
5633 HANDLE job, hproc, h, h2;
5634 BOOL b = init();
5635 ok(b, "Basic init of CreateProcess test\n");
5636 if (!b) return;
5637
5638 if (myARGC >= 3)
5639 {
5640 if (!strcmp(myARGV[2], "dump") && myARGC >= 4)
5641 {
5642 doChild(myARGV[3], (myARGC >= 5) ? myARGV[4] : NULL);
5643 return;
5644 }
5645 else if (!strcmp(myARGV[2], "wait"))
5646 {
5647 Sleep(30000);
5648 ok(0, "Child process not killed\n");
5649 return;
5650 }
5651 else if (!strcmp(myARGV[2], "sync") && myARGC >= 4)
5652 {
5653 HANDLE sem = OpenSemaphoreA(SYNCHRONIZE, FALSE, myARGV[3]);
5654 ok(sem != 0, "OpenSemaphoreA(%s) failed le=%lu\n", myARGV[3], GetLastError());
5655 if (sem)
5656 {
5657 DWORD ret = WaitForSingleObject(sem, 30000);
5658 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject(%s) returned %lu\n", myARGV[3], ret);
5659 CloseHandle(sem);
5660 }
5661 return;
5662 }
5663 else if (!strcmp(myARGV[2], "exit"))
5664 {
5665 return;
5666 }
5667 else if (!strcmp(myARGV[2], "nested") && myARGC >= 4)
5668 {
5669 char buffer[MAX_PATH + 26];
5670 STARTUPINFOA startup;
5671 PROCESS_INFORMATION info;
5672 HANDLE hFile;
5673
5674 memset(&startup, 0, sizeof(startup));
5675 startup.cb = sizeof(startup);
5676 startup.dwFlags = STARTF_USESHOWWINDOW;
5677 startup.wShowWindow = SW_SHOWNORMAL;
5678
5679 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, myARGV[3]);
5680 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n");
5681 CloseHandle(info.hProcess);
5682 CloseHandle(info.hThread);
5683
5684 /* The nested process is suspended so we can use the same resource
5685 * file and it's up to the parent to read it before resuming the
5686 * nested process.
5687 */
5688 hFile = CreateFileA(myARGV[3], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
5689 childPrintf(hFile, "[Nested]\nPid=%08lu\n", info.dwProcessId);
5690 CloseHandle(hFile);
5691 return;
5692 }
5693 else if (!strcmp(myARGV[2], "parent") && myARGC >= 5)
5694 {
5695 sscanf(myARGV[4], "%p", &h);
5696 test_parent_process_attribute(atoi(myARGV[3]), h);
5697 return;
5698 }
5699 else if (!strcmp(myARGV[2], "handlelist") && myARGC >= 5)
5700 {
5701 sscanf(myARGV[3], "%p", &h);
5702 sscanf(myARGV[4], "%p", &h2);
5703 test_handle_list_attribute(TRUE, h, h2);
5704 return;
5705 }
5706 else if (!strcmp(myARGV[2], "nested_jobs") && myARGC >= 4)
5707 {
5708 test_nested_jobs_child(atoi(myARGV[3]));
5709 return;
5710 }
5711
5712 ok(0, "Unexpected command %s\n", myARGV[2]);
5713 return;
5714 }
5715 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
5716 if (hproc)
5717 {
5718 test_process_info(hproc);
5719 CloseHandle(hproc);
5720 }
5721 else
5722 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
5723 test_process_info(GetCurrentProcess());
5724 test_TerminateProcess();
5725 test_Startup();
5726 test_CommandLine();
5727 test_Directory();
5728 test_Toolhelp();
5729 test_Environment();
5730 test_SuspendFlag();
5731 test_DebuggingFlag();
5732 test_Console();
5733 test_ExitCode();
5734 test_OpenProcess();
5735 test_GetProcessVersion();
5736 test_GetProcessImageFileNameA();
5737 test_QueryFullProcessImageNameA();
5738 test_QueryFullProcessImageNameW();
5739 test_Handles();
5740 test_IsWow64Process();
5741 test_IsWow64Process2();
5742 test_SystemInfo();
5743 test_ProcessorCount();
5744 test_RegistryQuota();
5745 test_DuplicateHandle();
5746 test_StdHandleInheritance();
5747 test_GetNumaProcessorNode();
5748 test_session_info();
5749 test_GetLogicalProcessorInformationEx();
5750 test_GetSystemCpuSetInformation();
5751 test_largepages();
5752 test_ProcThreadAttributeList();
5753 test_SuspendProcessState();
5754 test_SuspendProcessNewThread();
5755 test_parent_process_attribute(0, NULL);
5756 test_handle_list_attribute(FALSE, NULL, NULL);
5757 test_dead_process();
5758 test_services_exe();
5759 test_startupinfo();
5760 test_GetProcessInformation();
5761
5762 /* things that can be tested:
5763 * lookup: check the way program to be executed is searched
5764 * handles: check the handle inheritance stuff (+sec options)
5765 * console: check if console creation parameters work
5766 */
5767
5768#ifdef __REACTOS__
5769 if (is_reactos()) {
5770 ok(FALSE, "FIXME: ReactOS's job support is too basic for these tests.\n");
5771 return;
5772 }
5773#endif
5774 if (!pCreateJobObjectW)
5775 {
5776 win_skip("No job object support\n");
5777 return;
5778 }
5779
5780 test_IsProcessInJob();
5781 test_TerminateJobObject();
5782 test_QueryInformationJobObject();
5783 test_CompletionPort();
5784 test_KillOnJobClose();
5785 test_WaitForJobObject();
5786 test_nested_jobs();
5787 job = test_AddSelfToJob();
5788 test_jobInheritance(job);
5789 test_job_list_attribute(job);
5790 test_BreakawayOk(job);
5791 CloseHandle(job);
5792}