Reactos
at master 5792 lines 239 kB view raw
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}