1 /* 2 * Unit test suite for process functions 3 * 4 * Copyright 2002 Eric Pouech 5 * Copyright 2006 Dmitry Timoshkov 6 * Copyright 2014 Michael Müller 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #include <assert.h> 24 #include <stdarg.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 28 #include "ntstatus.h" 29 #define WIN32_NO_STATUS 30 #include "windef.h" 31 #include "winbase.h" 32 #include "winuser.h" 33 #include "wincon.h" 34 #include "winnls.h" 35 #include "winternl.h" 36 #include "tlhelp32.h" 37 38 #include "wine/test.h" 39 40 #include "winnt.h" 41 42 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */ 43 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000) 44 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */ 45 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff) 46 47 #define expect_eq_d(expected, actual) \ 48 do { \ 49 int value = (actual); \ 50 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \ 51 (expected), value); \ 52 } while (0) 53 #define expect_eq_s(expected, actual) \ 54 do { \ 55 LPCSTR value = (actual); \ 56 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \ 57 expected, value); \ 58 } while (0) 59 #define expect_eq_ws_i(expected, actual) \ 60 do { \ 61 LPCWSTR value = (actual); \ 62 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \ 63 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \ 64 } while (0) 65 66 static HINSTANCE hkernel32, hntdll; 67 static void (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO); 68 static BOOL (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD); 69 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL); 70 static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD); 71 static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD); 72 static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize); 73 static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize); 74 static DWORD (WINAPI *pK32GetProcessImageFileNameA)(HANDLE,LPSTR,DWORD); 75 static HANDLE (WINAPI *pCreateJobObjectW)(LPSECURITY_ATTRIBUTES sa, LPCWSTR name); 76 static BOOL (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process); 77 static BOOL (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result); 78 static BOOL (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code); 79 static BOOL (WINAPI *pQueryInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len, LPDWORD ret_len); 80 static BOOL (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len); 81 static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads); 82 static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR); 83 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); 84 static BOOL (WINAPI *pProcessIdToSessionId)(DWORD,DWORD*); 85 static DWORD (WINAPI *pWTSGetActiveConsoleSessionId)(void); 86 static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD); 87 static BOOL (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*); 88 static BOOL (WINAPI *pProcess32Next)(HANDLE, PROCESSENTRY32*); 89 static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*); 90 static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*); 91 static BOOL (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*); 92 static SIZE_T (WINAPI *pGetLargePageMinimum)(void); 93 static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*); 94 static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*); 95 static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*); 96 static DWORD (WINAPI *pGetActiveProcessorCount)(WORD); 97 98 /* ############################### */ 99 static char base[MAX_PATH]; 100 static char selfname[MAX_PATH]; 101 static char* exename; 102 static char resfile[MAX_PATH]; 103 104 static int myARGC; 105 static char** myARGV; 106 107 /* As some environment variables get very long on Unix, we only test for 108 * the first 127 bytes. 109 * Note that increasing this value past 256 may exceed the buffer size 110 * limitations of the *Profile functions (at least on Wine). 111 */ 112 #define MAX_LISTED_ENV_VAR 128 113 114 /* ---------------- portable memory allocation thingie */ 115 116 static char memory[1024*256]; 117 static char* memory_index = memory; 118 119 static char* grab_memory(size_t len) 120 { 121 char* ret = memory_index; 122 /* align on dword */ 123 len = (len + 3) & ~3; 124 memory_index += len; 125 assert(memory_index <= memory + sizeof(memory)); 126 return ret; 127 } 128 129 static void release_memory(void) 130 { 131 memory_index = memory; 132 } 133 134 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */ 135 136 static const char* encodeA(const char* str) 137 { 138 char* ptr; 139 size_t len,i; 140 141 if (!str) return ""; 142 len = strlen(str) + 1; 143 ptr = grab_memory(len * 2 + 1); 144 for (i = 0; i < len; i++) 145 sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]); 146 ptr[2 * len] = '\0'; 147 return ptr; 148 } 149 150 static const char* encodeW(const WCHAR* str) 151 { 152 char* ptr; 153 size_t len,i; 154 155 if (!str) return ""; 156 len = lstrlenW(str) + 1; 157 ptr = grab_memory(len * 4 + 1); 158 assert(ptr); 159 for (i = 0; i < len; i++) 160 sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]); 161 ptr[4 * len] = '\0'; 162 return ptr; 163 } 164 165 static unsigned decode_char(char c) 166 { 167 if (c >= '0' && c <= '9') return c - '0'; 168 if (c >= 'a' && c <= 'f') return c - 'a' + 10; 169 assert(c >= 'A' && c <= 'F'); 170 return c - 'A' + 10; 171 } 172 173 static char* decodeA(const char* str) 174 { 175 char* ptr; 176 size_t len,i; 177 178 len = strlen(str) / 2; 179 if (!len--) return NULL; 180 ptr = grab_memory(len + 1); 181 for (i = 0; i < len; i++) 182 ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]); 183 ptr[len] = '\0'; 184 return ptr; 185 } 186 187 /* This will be needed to decode Unicode strings saved by the child process 188 * when we test Unicode functions. 189 */ 190 static WCHAR* decodeW(const char* str) 191 { 192 size_t len; 193 WCHAR* ptr; 194 int i; 195 196 len = strlen(str) / 4; 197 if (!len--) return NULL; 198 ptr = (WCHAR*)grab_memory(len * 2 + 1); 199 for (i = 0; i < len; i++) 200 ptr[i] = (decode_char(str[4 * i]) << 12) | 201 (decode_char(str[4 * i + 1]) << 8) | 202 (decode_char(str[4 * i + 2]) << 4) | 203 (decode_char(str[4 * i + 3]) << 0); 204 ptr[len] = '\0'; 205 return ptr; 206 } 207 208 /****************************************************************** 209 * init 210 * 211 * generates basic information like: 212 * base: absolute path to curr dir 213 * selfname: the way to reinvoke ourselves 214 * exename: executable without the path 215 * function-pointers, which are not implemented in all windows versions 216 */ 217 static BOOL init(void) 218 { 219 char *p; 220 221 myARGC = winetest_get_mainargs( &myARGV ); 222 if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE; 223 strcpy(selfname, myARGV[0]); 224 225 /* Strip the path of selfname */ 226 if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1; 227 else exename = selfname; 228 229 if ((p = strrchr(exename, '/')) != NULL) exename = p + 1; 230 231 hkernel32 = GetModuleHandleA("kernel32"); 232 hntdll = GetModuleHandleA("ntdll.dll"); 233 234 pNtQueryInformationProcess = (void *)GetProcAddress(hntdll, "NtQueryInformationProcess"); 235 236 pGetNativeSystemInfo = (void *) GetProcAddress(hkernel32, "GetNativeSystemInfo"); 237 pGetSystemRegistryQuota = (void *) GetProcAddress(hkernel32, "GetSystemRegistryQuota"); 238 pIsWow64Process = (void *) GetProcAddress(hkernel32, "IsWow64Process"); 239 pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx"); 240 pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx"); 241 pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA"); 242 pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW"); 243 pK32GetProcessImageFileNameA = (void *) GetProcAddress(hkernel32, "K32GetProcessImageFileNameA"); 244 pCreateJobObjectW = (void *)GetProcAddress(hkernel32, "CreateJobObjectW"); 245 pAssignProcessToJobObject = (void *)GetProcAddress(hkernel32, "AssignProcessToJobObject"); 246 pIsProcessInJob = (void *)GetProcAddress(hkernel32, "IsProcessInJob"); 247 pTerminateJobObject = (void *)GetProcAddress(hkernel32, "TerminateJobObject"); 248 pQueryInformationJobObject = (void *)GetProcAddress(hkernel32, "QueryInformationJobObject"); 249 pSetInformationJobObject = (void *)GetProcAddress(hkernel32, "SetInformationJobObject"); 250 pCreateIoCompletionPort = (void *)GetProcAddress(hkernel32, "CreateIoCompletionPort"); 251 pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode"); 252 pProcessIdToSessionId = (void *)GetProcAddress(hkernel32, "ProcessIdToSessionId"); 253 pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId"); 254 pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot"); 255 pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First"); 256 pProcess32Next = (void *)GetProcAddress(hkernel32, "Process32Next"); 257 pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First"); 258 pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next"); 259 pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx"); 260 pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum"); 261 pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList"); 262 pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute"); 263 pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList"); 264 pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount"); 265 266 return TRUE; 267 } 268 269 /****************************************************************** 270 * get_file_name 271 * 272 * generates an absolute file_name for temporary file 273 * 274 */ 275 static void get_file_name(char* buf) 276 { 277 char path[MAX_PATH]; 278 279 buf[0] = '\0'; 280 GetTempPathA(sizeof(path), path); 281 GetTempFileNameA(path, "wt", 0, buf); 282 } 283 284 /****************************************************************** 285 * static void childPrintf 286 * 287 */ 288 static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...) 289 { 290 va_list valist; 291 char buffer[1024+4*MAX_LISTED_ENV_VAR]; 292 DWORD w; 293 294 va_start(valist, fmt); 295 vsprintf(buffer, fmt, valist); 296 va_end(valist); 297 WriteFile(h, buffer, strlen(buffer), &w, NULL); 298 } 299 300 301 /****************************************************************** 302 * doChild 303 * 304 * output most of the information in the child process 305 */ 306 static void doChild(const char* file, const char* option) 307 { 308 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters; 309 STARTUPINFOA siA; 310 STARTUPINFOW siW; 311 int i; 312 char *ptrA, *ptrA_save; 313 WCHAR *ptrW, *ptrW_save; 314 char bufA[MAX_PATH]; 315 WCHAR bufW[MAX_PATH]; 316 HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); 317 HANDLE snapshot; 318 PROCESSENTRY32 pe; 319 BOOL ret; 320 321 if (hFile == INVALID_HANDLE_VALUE) return; 322 323 /* output of startup info (Ansi) */ 324 GetStartupInfoA(&siA); 325 childPrintf(hFile, 326 "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n" 327 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n" 328 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n" 329 "dwFlags=%u\nwShowWindow=%u\n" 330 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n", 331 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle), 332 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize, 333 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute, 334 siA.dwFlags, siA.wShowWindow, 335 (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError); 336 337 /* check the console handles in the TEB */ 338 childPrintf(hFile, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n", 339 (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput, 340 (DWORD_PTR)params->hStdError); 341 342 /* since GetStartupInfoW is only implemented in win2k, 343 * zero out before calling so we can notice the difference 344 */ 345 memset(&siW, 0, sizeof(siW)); 346 GetStartupInfoW(&siW); 347 childPrintf(hFile, 348 "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n" 349 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n" 350 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n" 351 "dwFlags=%u\nwShowWindow=%u\n" 352 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n", 353 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle), 354 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize, 355 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute, 356 siW.dwFlags, siW.wShowWindow, 357 (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError); 358 359 /* Arguments */ 360 childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC); 361 for (i = 0; i < myARGC; i++) 362 { 363 childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i])); 364 } 365 childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA())); 366 childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW())); 367 368 /* output toolhelp information */ 369 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 370 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError()); 371 memset(&pe, 0, sizeof(pe)); 372 pe.dwSize = sizeof(pe); 373 if (pProcess32First(snapshot, &pe)) 374 { 375 while (pe.th32ProcessID != GetCurrentProcessId()) 376 if (!pProcess32Next(snapshot, &pe)) break; 377 } 378 CloseHandle(snapshot); 379 ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n"); 380 childPrintf(hFile, 381 "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n" 382 "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n" 383 "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n", 384 pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID, 385 pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase, 386 pe.dwFlags, encodeA(pe.szExeFile)); 387 388 /* output of environment (Ansi) */ 389 ptrA_save = ptrA = GetEnvironmentStringsA(); 390 if (ptrA) 391 { 392 char env_var[MAX_LISTED_ENV_VAR]; 393 394 childPrintf(hFile, "[EnvironmentA]\n"); 395 i = 0; 396 while (*ptrA) 397 { 398 lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR); 399 childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var)); 400 i++; 401 ptrA += strlen(ptrA) + 1; 402 } 403 childPrintf(hFile, "len=%d\n\n", i); 404 FreeEnvironmentStringsA(ptrA_save); 405 } 406 407 /* output of environment (Unicode) */ 408 ptrW_save = ptrW = GetEnvironmentStringsW(); 409 if (ptrW) 410 { 411 WCHAR env_var[MAX_LISTED_ENV_VAR]; 412 413 childPrintf(hFile, "[EnvironmentW]\n"); 414 i = 0; 415 while (*ptrW) 416 { 417 lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1); 418 env_var[MAX_LISTED_ENV_VAR - 1] = '\0'; 419 childPrintf(hFile, "env%d=%s\n", i, encodeW(env_var)); 420 i++; 421 ptrW += lstrlenW(ptrW) + 1; 422 } 423 childPrintf(hFile, "len=%d\n\n", i); 424 FreeEnvironmentStringsW(ptrW_save); 425 } 426 427 childPrintf(hFile, "[Misc]\n"); 428 if (GetCurrentDirectoryA(sizeof(bufA), bufA)) 429 childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA)); 430 if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW)) 431 childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW)); 432 childPrintf(hFile, "\n"); 433 434 if (option && strcmp(option, "console") == 0) 435 { 436 CONSOLE_SCREEN_BUFFER_INFO sbi; 437 HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE); 438 HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE); 439 DWORD modeIn, modeOut; 440 441 childPrintf(hFile, "[Console]\n"); 442 if (GetConsoleScreenBufferInfo(hConOut, &sbi)) 443 { 444 childPrintf(hFile, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n", 445 sbi.dwSize.X, sbi.dwSize.Y, sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y, sbi.wAttributes); 446 childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n", 447 sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom); 448 childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n", 449 sbi.dwMaximumWindowSize.X, sbi.dwMaximumWindowSize.Y); 450 } 451 childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n", 452 GetConsoleCP(), GetConsoleOutputCP()); 453 if (GetConsoleMode(hConIn, &modeIn)) 454 childPrintf(hFile, "InputMode=%u\n", modeIn); 455 if (GetConsoleMode(hConOut, &modeOut)) 456 childPrintf(hFile, "OutputMode=%u\n", modeOut); 457 458 /* now that we have written all relevant information, let's change it */ 459 SetLastError(0xdeadbeef); 460 ret = SetConsoleCP(1252); 461 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 462 { 463 win_skip("Setting the codepage is not implemented\n"); 464 } 465 else 466 { 467 ok(ret, "Setting CP\n"); 468 ok(SetConsoleOutputCP(1252), "Setting SB CP\n"); 469 } 470 471 ret = SetConsoleMode(hConIn, modeIn ^ 1); 472 ok( ret, "Setting mode (%d)\n", GetLastError()); 473 ret = SetConsoleMode(hConOut, modeOut ^ 1); 474 ok( ret, "Setting mode (%d)\n", GetLastError()); 475 sbi.dwCursorPosition.X ^= 1; 476 sbi.dwCursorPosition.Y ^= 1; 477 ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition); 478 ok( ret, "Setting cursor position (%d)\n", GetLastError()); 479 } 480 if (option && strcmp(option, "stdhandle") == 0) 481 { 482 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); 483 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 484 485 if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE) 486 { 487 char buf[1024]; 488 DWORD r, w; 489 490 ok(ReadFile(hStdIn, buf, sizeof(buf), &r, NULL) && r > 0, "Reading message from input pipe\n"); 491 childPrintf(hFile, "[StdHandle]\nmsg=%s\n\n", encodeA(buf)); 492 ok(WriteFile(hStdOut, buf, r, &w, NULL) && w == r, "Writing message to output pipe\n"); 493 } 494 } 495 496 if (option && strcmp(option, "exit_code") == 0) 497 { 498 childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123); 499 CloseHandle(hFile); 500 ExitProcess(123); 501 } 502 503 CloseHandle(hFile); 504 } 505 506 static char* getChildString(const char* sect, const char* key) 507 { 508 char buf[1024+4*MAX_LISTED_ENV_VAR]; 509 char* ret; 510 511 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile); 512 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL; 513 assert(!(strlen(buf) & 1)); 514 ret = decodeA(buf); 515 return ret; 516 } 517 518 static WCHAR* getChildStringW(const char* sect, const char* key) 519 { 520 char buf[1024+4*MAX_LISTED_ENV_VAR]; 521 WCHAR* ret; 522 523 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile); 524 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL; 525 assert(!(strlen(buf) & 1)); 526 ret = decodeW(buf); 527 return ret; 528 } 529 530 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by 531 * others... (windows uses stricmp while Un*x uses strcasecmp...) 532 */ 533 static int wtstrcasecmp(const char* p1, const char* p2) 534 { 535 char c1, c2; 536 537 c1 = c2 = '@'; 538 while (c1 == c2 && c1) 539 { 540 c1 = *p1++; c2 = *p2++; 541 if (c1 != c2) 542 { 543 c1 = toupper(c1); c2 = toupper(c2); 544 } 545 } 546 return c1 - c2; 547 } 548 549 static int strCmp(const char* s1, const char* s2, BOOL sensitive) 550 { 551 if (!s1 && !s2) return 0; 552 if (!s2) return -1; 553 if (!s1) return 1; 554 return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2); 555 } 556 557 static void ok_child_string( int line, const char *sect, const char *key, 558 const char *expect, int sensitive ) 559 { 560 char* result = getChildString( sect, key ); 561 ok_(__FILE__, line)( strCmp(result, expect, sensitive) == 0, "%s:%s expected '%s', got '%s'\n", 562 sect, key, expect ? expect : "(null)", result ); 563 } 564 565 static void ok_child_stringWA( int line, const char *sect, const char *key, 566 const char *expect, int sensitive ) 567 { 568 WCHAR* expectW; 569 CHAR* resultA; 570 DWORD len; 571 WCHAR* result = getChildStringW( sect, key ); 572 573 len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0); 574 expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); 575 MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len); 576 577 len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL); 578 resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR)); 579 WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL); 580 581 if (sensitive) 582 ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n", 583 sect, key, expect ? expect : "(null)", resultA ); 584 else 585 ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n", 586 sect, key, expect ? expect : "(null)", resultA ); 587 HeapFree(GetProcessHeap(),0,expectW); 588 HeapFree(GetProcessHeap(),0,resultA); 589 } 590 591 static void ok_child_int( int line, const char *sect, const char *key, UINT expect ) 592 { 593 UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile ); 594 ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result ); 595 } 596 597 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 ) 598 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 ) 599 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 ) 600 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect)) 601 602 static void test_Startup(void) 603 { 604 char buffer[MAX_PATH]; 605 PROCESS_INFORMATION info; 606 STARTUPINFOA startup,si; 607 char *result; 608 static CHAR title[] = "I'm the title string", 609 desktop[] = "winsta0\\default", 610 empty[] = ""; 611 612 /* let's start simplistic */ 613 memset(&startup, 0, sizeof(startup)); 614 startup.cb = sizeof(startup); 615 startup.dwFlags = STARTF_USESHOWWINDOW; 616 startup.wShowWindow = SW_SHOWNORMAL; 617 618 get_file_name(resfile); 619 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 620 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 621 /* wait for child to terminate */ 622 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 623 /* child process has changed result file, so let profile functions know about it */ 624 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 625 CloseHandle(info.hThread); 626 CloseHandle(info.hProcess); 627 628 GetStartupInfoA(&si); 629 okChildInt("StartupInfoA", "cb", startup.cb); 630 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop); 631 okChildInt("StartupInfoA", "dwX", startup.dwX); 632 okChildInt("StartupInfoA", "dwY", startup.dwY); 633 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 634 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 635 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 636 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 637 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 638 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 639 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 640 release_memory(); 641 DeleteFileA(resfile); 642 643 /* not so simplistic now */ 644 memset(&startup, 0, sizeof(startup)); 645 startup.cb = sizeof(startup); 646 startup.dwFlags = STARTF_USESHOWWINDOW; 647 startup.wShowWindow = SW_SHOWNORMAL; 648 startup.lpTitle = title; 649 startup.lpDesktop = desktop; 650 startup.dwXCountChars = 0x12121212; 651 startup.dwYCountChars = 0x23232323; 652 startup.dwX = 0x34343434; 653 startup.dwY = 0x45454545; 654 startup.dwXSize = 0x56565656; 655 startup.dwYSize = 0x67676767; 656 startup.dwFillAttribute = 0xA55A; 657 658 get_file_name(resfile); 659 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 660 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 661 /* wait for child to terminate */ 662 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 663 /* child process has changed result file, so let profile functions know about it */ 664 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 665 CloseHandle(info.hThread); 666 CloseHandle(info.hProcess); 667 668 okChildInt("StartupInfoA", "cb", startup.cb); 669 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); 670 okChildString("StartupInfoA", "lpTitle", startup.lpTitle); 671 okChildInt("StartupInfoA", "dwX", startup.dwX); 672 okChildInt("StartupInfoA", "dwY", startup.dwY); 673 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 674 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 675 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 676 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 677 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 678 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 679 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 680 release_memory(); 681 DeleteFileA(resfile); 682 683 /* not so simplistic now */ 684 memset(&startup, 0, sizeof(startup)); 685 startup.cb = sizeof(startup); 686 startup.dwFlags = STARTF_USESHOWWINDOW; 687 startup.wShowWindow = SW_SHOWNORMAL; 688 startup.lpTitle = title; 689 startup.lpDesktop = NULL; 690 startup.dwXCountChars = 0x12121212; 691 startup.dwYCountChars = 0x23232323; 692 startup.dwX = 0x34343434; 693 startup.dwY = 0x45454545; 694 startup.dwXSize = 0x56565656; 695 startup.dwYSize = 0x67676767; 696 startup.dwFillAttribute = 0xA55A; 697 698 get_file_name(resfile); 699 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 700 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 701 /* wait for child to terminate */ 702 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 703 /* child process has changed result file, so let profile functions know about it */ 704 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 705 CloseHandle(info.hThread); 706 CloseHandle(info.hProcess); 707 708 okChildInt("StartupInfoA", "cb", startup.cb); 709 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop); 710 okChildString("StartupInfoA", "lpTitle", startup.lpTitle); 711 okChildInt("StartupInfoA", "dwX", startup.dwX); 712 okChildInt("StartupInfoA", "dwY", startup.dwY); 713 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 714 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 715 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 716 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 717 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 718 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 719 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 720 release_memory(); 721 DeleteFileA(resfile); 722 723 /* not so simplistic now */ 724 memset(&startup, 0, sizeof(startup)); 725 startup.cb = sizeof(startup); 726 startup.dwFlags = STARTF_USESHOWWINDOW; 727 startup.wShowWindow = SW_SHOWNORMAL; 728 startup.lpTitle = title; 729 startup.lpDesktop = empty; 730 startup.dwXCountChars = 0x12121212; 731 startup.dwYCountChars = 0x23232323; 732 startup.dwX = 0x34343434; 733 startup.dwY = 0x45454545; 734 startup.dwXSize = 0x56565656; 735 startup.dwYSize = 0x67676767; 736 startup.dwFillAttribute = 0xA55A; 737 738 get_file_name(resfile); 739 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 740 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 741 /* wait for child to terminate */ 742 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 743 /* child process has changed result file, so let profile functions know about it */ 744 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 745 CloseHandle(info.hThread); 746 CloseHandle(info.hProcess); 747 748 okChildInt("StartupInfoA", "cb", startup.cb); 749 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); 750 okChildString("StartupInfoA", "lpTitle", startup.lpTitle); 751 okChildInt("StartupInfoA", "dwX", startup.dwX); 752 okChildInt("StartupInfoA", "dwY", startup.dwY); 753 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 754 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 755 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 756 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 757 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 758 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 759 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 760 release_memory(); 761 DeleteFileA(resfile); 762 763 /* not so simplistic now */ 764 memset(&startup, 0, sizeof(startup)); 765 startup.cb = sizeof(startup); 766 startup.dwFlags = STARTF_USESHOWWINDOW; 767 startup.wShowWindow = SW_SHOWNORMAL; 768 startup.lpTitle = NULL; 769 startup.lpDesktop = desktop; 770 startup.dwXCountChars = 0x12121212; 771 startup.dwYCountChars = 0x23232323; 772 startup.dwX = 0x34343434; 773 startup.dwY = 0x45454545; 774 startup.dwXSize = 0x56565656; 775 startup.dwYSize = 0x67676767; 776 startup.dwFillAttribute = 0xA55A; 777 778 get_file_name(resfile); 779 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 780 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 781 /* wait for child to terminate */ 782 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 783 /* child process has changed result file, so let profile functions know about it */ 784 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 785 CloseHandle(info.hThread); 786 CloseHandle(info.hProcess); 787 788 okChildInt("StartupInfoA", "cb", startup.cb); 789 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); 790 result = getChildString( "StartupInfoA", "lpTitle" ); 791 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )), 792 "expected '%s' or null, got '%s'\n", selfname, result ); 793 okChildInt("StartupInfoA", "dwX", startup.dwX); 794 okChildInt("StartupInfoA", "dwY", startup.dwY); 795 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 796 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 797 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 798 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 799 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 800 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 801 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 802 release_memory(); 803 DeleteFileA(resfile); 804 805 /* not so simplistic now */ 806 memset(&startup, 0, sizeof(startup)); 807 startup.cb = sizeof(startup); 808 startup.dwFlags = STARTF_USESHOWWINDOW; 809 startup.wShowWindow = SW_SHOWNORMAL; 810 startup.lpTitle = empty; 811 startup.lpDesktop = desktop; 812 startup.dwXCountChars = 0x12121212; 813 startup.dwYCountChars = 0x23232323; 814 startup.dwX = 0x34343434; 815 startup.dwY = 0x45454545; 816 startup.dwXSize = 0x56565656; 817 startup.dwYSize = 0x67676767; 818 startup.dwFillAttribute = 0xA55A; 819 820 get_file_name(resfile); 821 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 822 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 823 /* wait for child to terminate */ 824 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 825 /* child process has changed result file, so let profile functions know about it */ 826 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 827 CloseHandle(info.hThread); 828 CloseHandle(info.hProcess); 829 830 okChildInt("StartupInfoA", "cb", startup.cb); 831 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); 832 okChildString("StartupInfoA", "lpTitle", startup.lpTitle); 833 okChildInt("StartupInfoA", "dwX", startup.dwX); 834 okChildInt("StartupInfoA", "dwY", startup.dwY); 835 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 836 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 837 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 838 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 839 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 840 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 841 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 842 release_memory(); 843 DeleteFileA(resfile); 844 845 /* not so simplistic now */ 846 memset(&startup, 0, sizeof(startup)); 847 startup.cb = sizeof(startup); 848 startup.dwFlags = STARTF_USESHOWWINDOW; 849 startup.wShowWindow = SW_SHOWNORMAL; 850 startup.lpTitle = empty; 851 startup.lpDesktop = empty; 852 startup.dwXCountChars = 0x12121212; 853 startup.dwYCountChars = 0x23232323; 854 startup.dwX = 0x34343434; 855 startup.dwY = 0x45454545; 856 startup.dwXSize = 0x56565656; 857 startup.dwYSize = 0x67676767; 858 startup.dwFillAttribute = 0xA55A; 859 860 get_file_name(resfile); 861 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 862 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 863 /* wait for child to terminate */ 864 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 865 /* child process has changed result file, so let profile functions know about it */ 866 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 867 CloseHandle(info.hThread); 868 CloseHandle(info.hProcess); 869 870 okChildInt("StartupInfoA", "cb", startup.cb); 871 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop); 872 okChildString("StartupInfoA", "lpTitle", startup.lpTitle); 873 okChildInt("StartupInfoA", "dwX", startup.dwX); 874 okChildInt("StartupInfoA", "dwY", startup.dwY); 875 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 876 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 877 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 878 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 879 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 880 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 881 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 882 release_memory(); 883 DeleteFileA(resfile); 884 885 /* TODO: test for A/W and W/A and W/W */ 886 } 887 888 static void test_CommandLine(void) 889 { 890 char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p; 891 char buffer2[MAX_PATH]; 892 PROCESS_INFORMATION info; 893 STARTUPINFOA startup; 894 BOOL ret; 895 896 memset(&startup, 0, sizeof(startup)); 897 startup.cb = sizeof(startup); 898 startup.dwFlags = STARTF_USESHOWWINDOW; 899 startup.wShowWindow = SW_SHOWNORMAL; 900 901 /* the basics */ 902 get_file_name(resfile); 903 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile); 904 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 905 /* wait for child to terminate */ 906 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 907 /* child process has changed result file, so let profile functions know about it */ 908 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 909 CloseHandle(info.hThread); 910 CloseHandle(info.hProcess); 911 912 okChildInt("Arguments", "argcA", 5); 913 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe"); 914 okChildString("Arguments", "argvA5", NULL); 915 okChildString("Arguments", "CommandLineA", buffer); 916 release_memory(); 917 DeleteFileA(resfile); 918 919 memset(&startup, 0, sizeof(startup)); 920 startup.cb = sizeof(startup); 921 startup.dwFlags = STARTF_USESHOWWINDOW; 922 startup.wShowWindow = SW_SHOWNORMAL; 923 924 /* from François */ 925 get_file_name(resfile); 926 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile); 927 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 928 /* wait for child to terminate */ 929 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 930 /* child process has changed result file, so let profile functions know about it */ 931 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 932 CloseHandle(info.hThread); 933 CloseHandle(info.hProcess); 934 935 okChildInt("Arguments", "argcA", 7); 936 okChildString("Arguments", "argvA4", "a\"b\\"); 937 okChildString("Arguments", "argvA5", "c\""); 938 okChildString("Arguments", "argvA6", "d"); 939 okChildString("Arguments", "argvA7", NULL); 940 okChildString("Arguments", "CommandLineA", buffer); 941 release_memory(); 942 DeleteFileA(resfile); 943 944 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/ 945 get_file_name(resfile); 946 /* Use exename to avoid buffer containing things like 'C:' */ 947 sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile); 948 SetLastError(0xdeadbeef); 949 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 950 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); 951 /* wait for child to terminate */ 952 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 953 /* child process has changed result file, so let profile functions know about it */ 954 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 955 CloseHandle(info.hThread); 956 CloseHandle(info.hProcess); 957 sprintf(buffer, "./%s", exename); 958 okChildString("Arguments", "argvA0", buffer); 959 release_memory(); 960 DeleteFileA(resfile); 961 962 get_file_name(resfile); 963 /* Use exename to avoid buffer containing things like 'C:' */ 964 sprintf(buffer, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile); 965 SetLastError(0xdeadbeef); 966 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 967 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); 968 /* wait for child to terminate */ 969 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 970 /* child process has changed result file, so let profile functions know about it */ 971 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 972 CloseHandle(info.hThread); 973 CloseHandle(info.hProcess); 974 sprintf(buffer, ".\\%s", exename); 975 okChildString("Arguments", "argvA0", buffer); 976 release_memory(); 977 DeleteFileA(resfile); 978 979 get_file_name(resfile); 980 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart); 981 assert ( lpFilePart != 0); 982 *(lpFilePart -1 ) = 0; 983 p = strrchr(fullpath, '\\'); 984 /* Use exename to avoid buffer containing things like 'C:' */ 985 if (p) sprintf(buffer, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p, exename, resfile); 986 else sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile); 987 SetLastError(0xdeadbeef); 988 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 989 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); 990 /* wait for child to terminate */ 991 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 992 /* child process has changed result file, so let profile functions know about it */ 993 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 994 CloseHandle(info.hThread); 995 CloseHandle(info.hProcess); 996 if (p) sprintf(buffer, "..%s/%s", p, exename); 997 else sprintf(buffer, "./%s", exename); 998 okChildString("Arguments", "argvA0", buffer); 999 release_memory(); 1000 DeleteFileA(resfile); 1001 1002 /* Using AppName */ 1003 get_file_name(resfile); 1004 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart); 1005 assert ( lpFilePart != 0); 1006 *(lpFilePart -1 ) = 0; 1007 p = strrchr(fullpath, '\\'); 1008 /* Use exename to avoid buffer containing things like 'C:' */ 1009 if (p) sprintf(buffer, "..%s/%s", p, exename); 1010 else sprintf(buffer, "./%s", exename); 1011 sprintf(buffer2, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile); 1012 SetLastError(0xdeadbeef); 1013 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 1014 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); 1015 /* wait for child to terminate */ 1016 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1017 /* child process has changed result file, so let profile functions know about it */ 1018 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1019 CloseHandle(info.hThread); 1020 CloseHandle(info.hProcess); 1021 sprintf(buffer, "tests/process.c dump %s", resfile); 1022 okChildString("Arguments", "argvA0", "dummy"); 1023 okChildString("Arguments", "CommandLineA", buffer2); 1024 okChildStringWA("Arguments", "CommandLineW", buffer2); 1025 release_memory(); 1026 DeleteFileA(resfile); 1027 1028 if (0) /* Test crashes on NT-based Windows. */ 1029 { 1030 /* Test NULL application name and command line parameters. */ 1031 SetLastError(0xdeadbeef); 1032 ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 1033 ok(!ret, "CreateProcessA unexpectedly succeeded\n"); 1034 ok(GetLastError() == ERROR_INVALID_PARAMETER, 1035 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 1036 } 1037 1038 buffer[0] = '\0'; 1039 1040 /* Test empty application name parameter. */ 1041 SetLastError(0xdeadbeef); 1042 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 1043 ok(!ret, "CreateProcessA unexpectedly succeeded\n"); 1044 ok(GetLastError() == ERROR_PATH_NOT_FOUND || 1045 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ || 1046 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */, 1047 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); 1048 1049 buffer2[0] = '\0'; 1050 1051 /* Test empty application name and command line parameters. */ 1052 SetLastError(0xdeadbeef); 1053 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 1054 ok(!ret, "CreateProcessA unexpectedly succeeded\n"); 1055 ok(GetLastError() == ERROR_PATH_NOT_FOUND || 1056 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ || 1057 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */, 1058 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); 1059 1060 /* Test empty command line parameter. */ 1061 SetLastError(0xdeadbeef); 1062 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 1063 ok(!ret, "CreateProcessA unexpectedly succeeded\n"); 1064 ok(GetLastError() == ERROR_FILE_NOT_FOUND || 1065 GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ || 1066 GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ || 1067 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */, 1068 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 1069 1070 strcpy(buffer, "doesnotexist.exe"); 1071 strcpy(buffer2, "does not exist.exe"); 1072 1073 /* Test nonexistent application name. */ 1074 SetLastError(0xdeadbeef); 1075 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 1076 ok(!ret, "CreateProcessA unexpectedly succeeded\n"); 1077 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 1078 1079 SetLastError(0xdeadbeef); 1080 ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 1081 ok(!ret, "CreateProcessA unexpectedly succeeded\n"); 1082 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 1083 1084 /* Test nonexistent command line parameter. */ 1085 SetLastError(0xdeadbeef); 1086 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 1087 ok(!ret, "CreateProcessA unexpectedly succeeded\n"); 1088 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 1089 1090 SetLastError(0xdeadbeef); 1091 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); 1092 ok(!ret, "CreateProcessA unexpectedly succeeded\n"); 1093 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); 1094 } 1095 1096 static void test_Directory(void) 1097 { 1098 char buffer[MAX_PATH]; 1099 PROCESS_INFORMATION info; 1100 STARTUPINFOA startup; 1101 char windir[MAX_PATH]; 1102 static CHAR cmdline[] = "winver.exe"; 1103 1104 memset(&startup, 0, sizeof(startup)); 1105 startup.cb = sizeof(startup); 1106 startup.dwFlags = STARTF_USESHOWWINDOW; 1107 startup.wShowWindow = SW_SHOWNORMAL; 1108 1109 /* the basics */ 1110 get_file_name(resfile); 1111 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 1112 GetWindowsDirectoryA( windir, sizeof(windir) ); 1113 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n"); 1114 /* wait for child to terminate */ 1115 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1116 /* child process has changed result file, so let profile functions know about it */ 1117 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1118 CloseHandle(info.hThread); 1119 CloseHandle(info.hProcess); 1120 1121 okChildIString("Misc", "CurrDirA", windir); 1122 release_memory(); 1123 DeleteFileA(resfile); 1124 1125 /* search PATH for the exe if directory is NULL */ 1126 ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 1127 ok(TerminateProcess(info.hProcess, 0), "Child process termination\n"); 1128 CloseHandle(info.hThread); 1129 CloseHandle(info.hProcess); 1130 1131 /* if any directory is provided, don't search PATH, error on bad directory */ 1132 SetLastError(0xdeadbeef); 1133 memset(&info, 0, sizeof(info)); 1134 ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, 1135 NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n"); 1136 ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", GetLastError()); 1137 ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n"); 1138 } 1139 1140 static void test_Toolhelp(void) 1141 { 1142 char buffer[MAX_PATH]; 1143 STARTUPINFOA startup; 1144 PROCESS_INFORMATION info; 1145 HANDLE process, thread, snapshot; 1146 PROCESSENTRY32 pe; 1147 THREADENTRY32 te; 1148 DWORD ret; 1149 int i; 1150 1151 #if defined(__REACTOS__) && defined(_M_AMD64) 1152 if (!winetest_interactive) 1153 { 1154 skip("ROSTESTS-372: Skipping test in kernel32_winetest:process test_Toolhelp because it leaves a process behind on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n"); 1155 //return; 1156 } 1157 #endif 1158 1159 memset(&startup, 0, sizeof(startup)); 1160 startup.cb = sizeof(startup); 1161 startup.dwFlags = STARTF_USESHOWWINDOW; 1162 startup.wShowWindow = SW_SHOWNORMAL; 1163 1164 get_file_name(resfile); 1165 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 1166 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n"); 1167 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1168 CloseHandle(info.hProcess); 1169 CloseHandle(info.hThread); 1170 1171 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1172 okChildInt("Toolhelp", "cntUsage", 0); 1173 okChildInt("Toolhelp", "th32DefaultHeapID", 0); 1174 okChildInt("Toolhelp", "th32ModuleID", 0); 1175 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId()); 1176 /* pcPriClassBase differs between Windows versions (either 6 or 8) */ 1177 okChildInt("Toolhelp", "dwFlags", 0); 1178 1179 release_memory(); 1180 DeleteFileA(resfile); 1181 1182 #if defined(__REACTOS__) && defined(_M_AMD64) 1183 if (!winetest_interactive) 1184 { 1185 skip("ROSTESTS-371: Skipping kernel32_winetest:sync test_apc_deadlock because it fails on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n"); 1186 } 1187 else 1188 { 1189 #endif 1190 1191 get_file_name(resfile); 1192 sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile); 1193 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n"); 1194 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1195 1196 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId); 1197 ok(process != NULL, "OpenProcess failed %u\n", GetLastError()); 1198 CloseHandle(process); 1199 1200 CloseHandle(info.hProcess); 1201 CloseHandle(info.hThread); 1202 #if defined(__REACTOS__) && defined(_M_AMD64) 1203 } 1204 #endif 1205 1206 for (i = 0; i < 20; i++) 1207 { 1208 SetLastError(0xdeadbeef); 1209 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId); 1210 ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError()); 1211 if (!process) break; 1212 CloseHandle(process); 1213 Sleep(100); 1214 } 1215 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */ 1216 ok(i < 20 || broken(i == 20), "process object not released\n"); 1217 1218 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 1219 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError()); 1220 memset(&pe, 0, sizeof(pe)); 1221 pe.dwSize = sizeof(pe); 1222 if (pProcess32First(snapshot, &pe)) 1223 { 1224 while (pe.th32ParentProcessID != info.dwProcessId) 1225 if (!pProcess32Next(snapshot, &pe)) break; 1226 } 1227 CloseHandle(snapshot); 1228 ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n"); 1229 1230 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID); 1231 ok(process != NULL, "OpenProcess failed %u\n", GetLastError()); 1232 1233 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 1234 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError()); 1235 memset(&te, 0, sizeof(te)); 1236 te.dwSize = sizeof(te); 1237 if (pThread32First(snapshot, &te)) 1238 { 1239 while (te.th32OwnerProcessID != pe.th32ProcessID) 1240 if (!pThread32Next(snapshot, &te)) break; 1241 } 1242 CloseHandle(snapshot); 1243 ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n"); 1244 1245 thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID); 1246 ok(thread != NULL, "OpenThread failed %u\n", GetLastError()); 1247 ret = ResumeThread(thread); 1248 ok(ret == 1, "expected 1, got %u\n", ret); 1249 CloseHandle(thread); 1250 1251 ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1252 CloseHandle(process); 1253 1254 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1255 okChildInt("Toolhelp", "cntUsage", 0); 1256 okChildInt("Toolhelp", "th32DefaultHeapID", 0); 1257 okChildInt("Toolhelp", "th32ModuleID", 0); 1258 okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId); 1259 /* pcPriClassBase differs between Windows versions (either 6 or 8) */ 1260 okChildInt("Toolhelp", "dwFlags", 0); 1261 1262 release_memory(); 1263 DeleteFileA(resfile); 1264 } 1265 1266 static BOOL is_str_env_drive_dir(const char* str) 1267 { 1268 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' && 1269 str[3] == '=' && str[4] == str[1]; 1270 } 1271 1272 /* compared expected child's environment (in gesA) from actual 1273 * environment our child got 1274 */ 1275 static void cmpEnvironment(const char* gesA) 1276 { 1277 int i, clen; 1278 const char* ptrA; 1279 char* res; 1280 char key[32]; 1281 BOOL found; 1282 1283 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile); 1284 1285 /* now look each parent env in child */ 1286 if ((ptrA = gesA) != NULL) 1287 { 1288 while (*ptrA) 1289 { 1290 for (i = 0; i < clen; i++) 1291 { 1292 sprintf(key, "env%d", i); 1293 res = getChildString("EnvironmentA", key); 1294 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0) 1295 break; 1296 } 1297 found = i < clen; 1298 ok(found, "Parent-env string %s isn't in child process\n", ptrA); 1299 1300 ptrA += strlen(ptrA) + 1; 1301 release_memory(); 1302 } 1303 } 1304 /* and each child env in parent */ 1305 for (i = 0; i < clen; i++) 1306 { 1307 sprintf(key, "env%d", i); 1308 res = getChildString("EnvironmentA", key); 1309 if ((ptrA = gesA) != NULL) 1310 { 1311 while (*ptrA) 1312 { 1313 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0) 1314 break; 1315 ptrA += strlen(ptrA) + 1; 1316 } 1317 if (!*ptrA) ptrA = NULL; 1318 } 1319 1320 if (!is_str_env_drive_dir(res)) 1321 { 1322 found = ptrA != NULL; 1323 ok(found, "Child-env string %s isn't in parent process\n", res); 1324 } 1325 /* else => should also test we get the right per drive default directory here... */ 1326 } 1327 } 1328 1329 static void test_Environment(void) 1330 { 1331 char buffer[MAX_PATH]; 1332 PROCESS_INFORMATION info; 1333 STARTUPINFOA startup; 1334 char *child_env; 1335 int child_env_len; 1336 char *ptr; 1337 char *ptr2; 1338 char *env; 1339 int slen; 1340 1341 memset(&startup, 0, sizeof(startup)); 1342 startup.cb = sizeof(startup); 1343 startup.dwFlags = STARTF_USESHOWWINDOW; 1344 startup.wShowWindow = SW_SHOWNORMAL; 1345 1346 /* the basics */ 1347 get_file_name(resfile); 1348 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 1349 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); 1350 /* wait for child to terminate */ 1351 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1352 /* child process has changed result file, so let profile functions know about it */ 1353 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1354 1355 env = GetEnvironmentStringsA(); 1356 cmpEnvironment(env); 1357 release_memory(); 1358 DeleteFileA(resfile); 1359 1360 memset(&startup, 0, sizeof(startup)); 1361 startup.cb = sizeof(startup); 1362 startup.dwFlags = STARTF_USESHOWWINDOW; 1363 startup.wShowWindow = SW_SHOWNORMAL; 1364 1365 /* the basics */ 1366 get_file_name(resfile); 1367 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 1368 1369 child_env_len = 0; 1370 ptr = env; 1371 while(*ptr) 1372 { 1373 slen = strlen(ptr)+1; 1374 child_env_len += slen; 1375 ptr += slen; 1376 } 1377 /* Add space for additional environment variables */ 1378 child_env_len += 256; 1379 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len); 1380 1381 ptr = child_env; 1382 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR"); 1383 ptr += strlen(ptr) + 1; 1384 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR"); 1385 ptr += strlen(ptr) + 1; 1386 strcpy(ptr, "FOO=BAR"); 1387 ptr += strlen(ptr) + 1; 1388 strcpy(ptr, "BAR=FOOBAR"); 1389 ptr += strlen(ptr) + 1; 1390 /* copy all existing variables except: 1391 * - WINELOADER 1392 * - PATH (already set above) 1393 * - the directory definitions (=[A-Z]:=) 1394 */ 1395 for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1) 1396 { 1397 if (strncmp(ptr2, "PATH=", 5) != 0 && 1398 strncmp(ptr2, "WINELOADER=", 11) != 0 && 1399 !is_str_env_drive_dir(ptr2)) 1400 { 1401 strcpy(ptr, ptr2); 1402 ptr += strlen(ptr) + 1; 1403 } 1404 } 1405 *ptr = '\0'; 1406 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n"); 1407 /* wait for child to terminate */ 1408 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1409 /* child process has changed result file, so let profile functions know about it */ 1410 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1411 1412 cmpEnvironment(child_env); 1413 1414 HeapFree(GetProcessHeap(), 0, child_env); 1415 FreeEnvironmentStringsA(env); 1416 release_memory(); 1417 DeleteFileA(resfile); 1418 } 1419 1420 static void test_SuspendFlag(void) 1421 { 1422 char buffer[MAX_PATH]; 1423 PROCESS_INFORMATION info; 1424 STARTUPINFOA startup, us; 1425 DWORD exit_status; 1426 char *result; 1427 1428 /* let's start simplistic */ 1429 memset(&startup, 0, sizeof(startup)); 1430 startup.cb = sizeof(startup); 1431 startup.dwFlags = STARTF_USESHOWWINDOW; 1432 startup.wShowWindow = SW_SHOWNORMAL; 1433 1434 get_file_name(resfile); 1435 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 1436 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n"); 1437 1438 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n"); 1439 Sleep(1000); 1440 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n"); 1441 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n"); 1442 1443 /* wait for child to terminate */ 1444 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1445 /* child process has changed result file, so let profile functions know about it */ 1446 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1447 1448 GetStartupInfoA(&us); 1449 1450 okChildInt("StartupInfoA", "cb", startup.cb); 1451 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop); 1452 result = getChildString( "StartupInfoA", "lpTitle" ); 1453 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )), 1454 "expected '%s' or null, got '%s'\n", selfname, result ); 1455 okChildInt("StartupInfoA", "dwX", startup.dwX); 1456 okChildInt("StartupInfoA", "dwY", startup.dwY); 1457 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 1458 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 1459 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 1460 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 1461 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 1462 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 1463 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 1464 release_memory(); 1465 DeleteFileA(resfile); 1466 } 1467 1468 static void test_DebuggingFlag(void) 1469 { 1470 char buffer[MAX_PATH]; 1471 void *processbase = NULL; 1472 PROCESS_INFORMATION info; 1473 STARTUPINFOA startup, us; 1474 DEBUG_EVENT de; 1475 unsigned dbg = 0; 1476 char *result; 1477 1478 /* let's start simplistic */ 1479 memset(&startup, 0, sizeof(startup)); 1480 startup.cb = sizeof(startup); 1481 startup.dwFlags = STARTF_USESHOWWINDOW; 1482 startup.wShowWindow = SW_SHOWNORMAL; 1483 1484 get_file_name(resfile); 1485 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 1486 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n"); 1487 1488 /* get all startup events up to the entry point break exception */ 1489 do 1490 { 1491 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); 1492 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); 1493 if (!dbg) 1494 { 1495 ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, 1496 "first event: %d\n", de.dwDebugEventCode); 1497 processbase = de.u.CreateProcessInfo.lpBaseOfImage; 1498 } 1499 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++; 1500 ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT || 1501 de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n"); 1502 } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT); 1503 1504 ok(dbg, "I have seen a debug event\n"); 1505 /* wait for child to terminate */ 1506 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1507 /* child process has changed result file, so let profile functions know about it */ 1508 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1509 1510 GetStartupInfoA(&us); 1511 1512 okChildInt("StartupInfoA", "cb", startup.cb); 1513 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop); 1514 result = getChildString( "StartupInfoA", "lpTitle" ); 1515 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )), 1516 "expected '%s' or null, got '%s'\n", selfname, result ); 1517 okChildInt("StartupInfoA", "dwX", startup.dwX); 1518 okChildInt("StartupInfoA", "dwY", startup.dwY); 1519 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 1520 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 1521 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 1522 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 1523 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 1524 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 1525 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 1526 release_memory(); 1527 DeleteFileA(resfile); 1528 } 1529 1530 static BOOL is_console(HANDLE h) 1531 { 1532 return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3; 1533 } 1534 1535 static void test_Console(void) 1536 { 1537 char buffer[MAX_PATH]; 1538 PROCESS_INFORMATION info; 1539 STARTUPINFOA startup, us; 1540 SECURITY_ATTRIBUTES sa; 1541 CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC; 1542 DWORD modeIn, modeOut, modeInC, modeOutC; 1543 DWORD cpIn, cpOut, cpInC, cpOutC; 1544 DWORD w; 1545 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut; 1546 const char* msg = "This is a std-handle inheritance test."; 1547 unsigned msg_len; 1548 BOOL run_tests = TRUE; 1549 char *result; 1550 1551 memset(&startup, 0, sizeof(startup)); 1552 startup.cb = sizeof(startup); 1553 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; 1554 startup.wShowWindow = SW_SHOWNORMAL; 1555 1556 sa.nLength = sizeof(sa); 1557 sa.lpSecurityDescriptor = NULL; 1558 sa.bInheritHandle = TRUE; 1559 1560 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0); 1561 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0); 1562 1563 /* first, we need to be sure we're attached to a console */ 1564 if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput)) 1565 { 1566 /* we're not attached to a console, let's do it */ 1567 AllocConsole(); 1568 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0); 1569 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0); 1570 } 1571 /* now verify everything's ok */ 1572 ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n"); 1573 ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n"); 1574 startup.hStdError = startup.hStdOutput; 1575 1576 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n"); 1577 ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n"); 1578 ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n"); 1579 cpIn = GetConsoleCP(); 1580 cpOut = GetConsoleOutputCP(); 1581 1582 get_file_name(resfile); 1583 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile); 1584 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n"); 1585 1586 /* wait for child to terminate */ 1587 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1588 /* child process has changed result file, so let profile functions know about it */ 1589 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1590 1591 /* now get the modification the child has made, and resets parents expected values */ 1592 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n"); 1593 ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n"); 1594 ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n"); 1595 1596 SetConsoleMode(startup.hStdInput, modeIn); 1597 SetConsoleMode(startup.hStdOutput, modeOut); 1598 1599 cpInC = GetConsoleCP(); 1600 cpOutC = GetConsoleOutputCP(); 1601 1602 /* Try to set invalid CP */ 1603 SetLastError(0xdeadbeef); 1604 ok(!SetConsoleCP(0), "Shouldn't succeed\n"); 1605 ok(GetLastError()==ERROR_INVALID_PARAMETER || 1606 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ 1607 "GetLastError: expecting %u got %u\n", 1608 ERROR_INVALID_PARAMETER, GetLastError()); 1609 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 1610 run_tests = FALSE; 1611 1612 1613 SetLastError(0xdeadbeef); 1614 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n"); 1615 ok(GetLastError()==ERROR_INVALID_PARAMETER || 1616 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ 1617 "GetLastError: expecting %u got %u\n", 1618 ERROR_INVALID_PARAMETER, GetLastError()); 1619 1620 SetConsoleCP(cpIn); 1621 SetConsoleOutputCP(cpOut); 1622 1623 GetStartupInfoA(&us); 1624 1625 okChildInt("StartupInfoA", "cb", startup.cb); 1626 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop); 1627 result = getChildString( "StartupInfoA", "lpTitle" ); 1628 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )), 1629 "expected '%s' or null, got '%s'\n", selfname, result ); 1630 okChildInt("StartupInfoA", "dwX", startup.dwX); 1631 okChildInt("StartupInfoA", "dwY", startup.dwY); 1632 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); 1633 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize); 1634 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars); 1635 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars); 1636 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute); 1637 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags); 1638 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); 1639 1640 /* check child correctly inherited the console */ 1641 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput); 1642 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput); 1643 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError); 1644 okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X); 1645 okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y); 1646 okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X); 1647 okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y); 1648 okChildInt("Console", "Attributes", sbi.wAttributes); 1649 okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left); 1650 okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top); 1651 okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right); 1652 okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom); 1653 okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X); 1654 okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y); 1655 okChildInt("Console", "InputCP", cpIn); 1656 okChildInt("Console", "OutputCP", cpOut); 1657 okChildInt("Console", "InputMode", modeIn); 1658 okChildInt("Console", "OutputMode", modeOut); 1659 1660 if (run_tests) 1661 { 1662 ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn); 1663 ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut); 1664 } 1665 else 1666 win_skip("Setting the codepage is not implemented\n"); 1667 1668 ok(modeInC == (modeIn ^ 1), "Wrong console mode\n"); 1669 ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n"); 1670 trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X); 1671 ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n"); 1672 1673 release_memory(); 1674 DeleteFileA(resfile); 1675 1676 ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n"); 1677 ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(), 1678 &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS), 1679 "Duplicating as inheritable child-output pipe\n"); 1680 CloseHandle(hChildOut); 1681 1682 ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n"); 1683 ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(), 1684 &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS), 1685 "Duplicating as inheritable child-input pipe\n"); 1686 CloseHandle(hChildIn); 1687 1688 memset(&startup, 0, sizeof(startup)); 1689 startup.cb = sizeof(startup); 1690 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; 1691 startup.wShowWindow = SW_SHOWNORMAL; 1692 startup.hStdInput = hChildInInh; 1693 startup.hStdOutput = hChildOutInh; 1694 startup.hStdError = hChildOutInh; 1695 1696 get_file_name(resfile); 1697 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile); 1698 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n"); 1699 ok(CloseHandle(hChildInInh), "Closing handle\n"); 1700 ok(CloseHandle(hChildOutInh), "Closing handle\n"); 1701 1702 msg_len = strlen(msg) + 1; 1703 ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n"); 1704 ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w); 1705 memset(buffer, 0, sizeof(buffer)); 1706 ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n"); 1707 ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg); 1708 1709 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */ 1710 ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL); 1711 1712 /* wait for child to terminate */ 1713 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1714 /* child process has changed result file, so let profile functions know about it */ 1715 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1716 1717 okChildString("StdHandle", "msg", msg); 1718 1719 release_memory(); 1720 DeleteFileA(resfile); 1721 } 1722 1723 static void test_ExitCode(void) 1724 { 1725 char buffer[MAX_PATH]; 1726 PROCESS_INFORMATION info; 1727 STARTUPINFOA startup; 1728 DWORD code; 1729 1730 /* let's start simplistic */ 1731 memset(&startup, 0, sizeof(startup)); 1732 startup.cb = sizeof(startup); 1733 startup.dwFlags = STARTF_USESHOWWINDOW; 1734 startup.wShowWindow = SW_SHOWNORMAL; 1735 1736 get_file_name(resfile); 1737 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile); 1738 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n"); 1739 1740 /* wait for child to terminate */ 1741 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 1742 /* child process has changed result file, so let profile functions know about it */ 1743 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 1744 1745 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n"); 1746 okChildInt("ExitCode", "value", code); 1747 1748 release_memory(); 1749 DeleteFileA(resfile); 1750 } 1751 1752 static void test_OpenProcess(void) 1753 { 1754 HANDLE hproc; 1755 void *addr1; 1756 MEMORY_BASIC_INFORMATION info; 1757 SIZE_T dummy, read_bytes; 1758 BOOL ret; 1759 1760 /* not exported in all windows versions */ 1761 if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) { 1762 win_skip("VirtualAllocEx not found\n"); 1763 return; 1764 } 1765 1766 /* without PROCESS_VM_OPERATION */ 1767 hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId()); 1768 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError()); 1769 1770 SetLastError(0xdeadbeef); 1771 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); 1772 ok(!addr1, "VirtualAllocEx should fail\n"); 1773 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 1774 { /* Win9x */ 1775 CloseHandle(hproc); 1776 win_skip("VirtualAllocEx not implemented\n"); 1777 return; 1778 } 1779 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); 1780 1781 read_bytes = 0xdeadbeef; 1782 SetLastError(0xdeadbeef); 1783 ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes); 1784 ok(ret, "ReadProcessMemory error %d\n", GetLastError()); 1785 ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes); 1786 1787 CloseHandle(hproc); 1788 1789 hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId()); 1790 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError()); 1791 1792 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); 1793 ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError()); 1794 1795 /* without PROCESS_QUERY_INFORMATION */ 1796 SetLastError(0xdeadbeef); 1797 ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)), 1798 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n"); 1799 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); 1800 1801 /* without PROCESS_VM_READ */ 1802 read_bytes = 0xdeadbeef; 1803 SetLastError(0xdeadbeef); 1804 ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes), 1805 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n"); 1806 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); 1807 ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes); 1808 1809 CloseHandle(hproc); 1810 1811 hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); 1812 1813 memset(&info, 0xcc, sizeof(info)); 1814 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info)); 1815 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError()); 1816 1817 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); 1818 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); 1819 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); 1820 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize); 1821 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); 1822 /* NT reports Protect == 0 for a not committed memory block */ 1823 ok(info.Protect == 0 /* NT */ || 1824 info.Protect == PAGE_NOACCESS, /* Win9x */ 1825 "%x != PAGE_NOACCESS\n", info.Protect); 1826 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); 1827 1828 SetLastError(0xdeadbeef); 1829 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE), 1830 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n"); 1831 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); 1832 1833 CloseHandle(hproc); 1834 1835 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId()); 1836 if (hproc) 1837 { 1838 SetLastError(0xdeadbeef); 1839 memset(&info, 0xcc, sizeof(info)); 1840 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info)); 1841 if (read_bytes) /* win8 */ 1842 { 1843 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError()); 1844 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1); 1845 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1); 1846 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect); 1847 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize); 1848 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); 1849 ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect); 1850 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); 1851 } 1852 else /* before win8 */ 1853 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); 1854 1855 SetLastError(0xdeadbeef); 1856 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE), 1857 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n"); 1858 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); 1859 1860 CloseHandle(hproc); 1861 } 1862 1863 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n"); 1864 } 1865 1866 static void test_GetProcessVersion(void) 1867 { 1868 static char cmdline[] = "winver.exe"; 1869 PROCESS_INFORMATION pi; 1870 STARTUPINFOA si; 1871 DWORD ret; 1872 1873 SetLastError(0xdeadbeef); 1874 ret = GetProcessVersion(0); 1875 ok(ret, "GetProcessVersion error %u\n", GetLastError()); 1876 1877 SetLastError(0xdeadbeef); 1878 ret = GetProcessVersion(GetCurrentProcessId()); 1879 ok(ret, "GetProcessVersion error %u\n", GetLastError()); 1880 1881 memset(&si, 0, sizeof(si)); 1882 si.cb = sizeof(si); 1883 si.dwFlags = STARTF_USESHOWWINDOW; 1884 si.wShowWindow = SW_HIDE; 1885 SetLastError(0xdeadbeef); 1886 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 1887 ok(ret, "CreateProcess error %u\n", GetLastError()); 1888 1889 SetLastError(0xdeadbeef); 1890 ret = GetProcessVersion(pi.dwProcessId); 1891 ok(ret, "GetProcessVersion error %u\n", GetLastError()); 1892 1893 SetLastError(0xdeadbeef); 1894 ret = TerminateProcess(pi.hProcess, 0); 1895 ok(ret, "TerminateProcess error %u\n", GetLastError()); 1896 1897 CloseHandle(pi.hProcess); 1898 CloseHandle(pi.hThread); 1899 } 1900 1901 static void test_GetProcessImageFileNameA(void) 1902 { 1903 DWORD rc; 1904 CHAR process[MAX_PATH]; 1905 static const char harddisk[] = "\\Device\\HarddiskVolume"; 1906 1907 if (!pK32GetProcessImageFileNameA) 1908 { 1909 win_skip("K32GetProcessImageFileNameA is unavailable\n"); 1910 return; 1911 } 1912 1913 /* callers must guess the buffer size */ 1914 SetLastError(0xdeadbeef); 1915 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0); 1916 ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER, 1917 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError()); 1918 1919 *process = '\0'; 1920 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process)); 1921 expect_eq_d(rc, lstrlenA(process)); 1922 if (strncmp(process, harddisk, lstrlenA(harddisk))) 1923 { 1924 todo_wine win_skip("%s is probably on a network share, skipping tests\n", process); 1925 return; 1926 } 1927 1928 if (!pQueryFullProcessImageNameA) 1929 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n"); 1930 else 1931 { 1932 CHAR image[MAX_PATH]; 1933 DWORD length; 1934 1935 length = sizeof(image); 1936 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length)); 1937 expect_eq_d(length, lstrlenA(image)); 1938 ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image); 1939 } 1940 } 1941 1942 static void test_QueryFullProcessImageNameA(void) 1943 { 1944 #define INIT_STR "Just some words" 1945 DWORD length, size; 1946 CHAR buf[MAX_PATH], module[MAX_PATH]; 1947 1948 if (!pQueryFullProcessImageNameA) 1949 { 1950 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n"); 1951 return; 1952 } 1953 1954 *module = '\0'; 1955 SetLastError(0); /* old Windows don't reset it on success */ 1956 size = GetModuleFileNameA(NULL, module, sizeof(module)); 1957 ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError()); 1958 1959 /* get the buffer length without \0 terminator */ 1960 length = sizeof(buf); 1961 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length)); 1962 expect_eq_d(length, lstrlenA(buf)); 1963 ok((buf[0] == '\\' && buf[1] == '\\') || 1964 lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module); 1965 1966 /* when the buffer is too small 1967 * - function fail with error ERROR_INSUFFICIENT_BUFFER 1968 * - the size variable is not modified 1969 * tested with the biggest too small size 1970 */ 1971 size = length; 1972 sprintf(buf,INIT_STR); 1973 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size)); 1974 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); 1975 expect_eq_d(length, size); 1976 expect_eq_s(INIT_STR, buf); 1977 1978 /* retest with smaller buffer size 1979 */ 1980 size = 4; 1981 sprintf(buf,INIT_STR); 1982 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size)); 1983 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); 1984 expect_eq_d(4, size); 1985 expect_eq_s(INIT_STR, buf); 1986 1987 /* this is a difference between the ascii and the unicode version 1988 * the unicode version crashes when the size is big enough to hold 1989 * the result while the ascii version throws an error 1990 */ 1991 size = 1024; 1992 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size)); 1993 expect_eq_d(1024, size); 1994 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError()); 1995 } 1996 1997 static void test_QueryFullProcessImageNameW(void) 1998 { 1999 HANDLE hSelf; 2000 WCHAR module_name[1024], device[1024]; 2001 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0}; 2002 WCHAR buf[1024]; 2003 DWORD size, len; 2004 2005 if (!pQueryFullProcessImageNameW) 2006 { 2007 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n"); 2008 return; 2009 } 2010 2011 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n"); 2012 2013 /* GetCurrentProcess pseudo-handle */ 2014 size = sizeof(buf) / sizeof(buf[0]); 2015 expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size)); 2016 expect_eq_d(lstrlenW(buf), size); 2017 expect_eq_ws_i(buf, module_name); 2018 2019 hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId()); 2020 /* Real handle */ 2021 size = sizeof(buf) / sizeof(buf[0]); 2022 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size)); 2023 expect_eq_d(lstrlenW(buf), size); 2024 expect_eq_ws_i(buf, module_name); 2025 2026 /* Buffer too small */ 2027 size = lstrlenW(module_name)/2; 2028 lstrcpyW(buf, deviceW); 2029 SetLastError(0xdeadbeef); 2030 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size)); 2031 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */ 2032 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); 2033 expect_eq_ws_i(deviceW, buf); /* buffer not changed */ 2034 2035 /* Too small - not space for NUL terminator */ 2036 size = lstrlenW(module_name); 2037 SetLastError(0xdeadbeef); 2038 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size)); 2039 expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */ 2040 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); 2041 2042 /* NULL buffer */ 2043 size = 0; 2044 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size)); 2045 expect_eq_d(0, size); 2046 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); 2047 2048 /* Buffer too small */ 2049 size = lstrlenW(module_name)/2; 2050 SetLastError(0xdeadbeef); 2051 lstrcpyW(buf, module_name); 2052 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size)); 2053 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */ 2054 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); 2055 expect_eq_ws_i(module_name, buf); /* buffer not changed */ 2056 2057 2058 /* native path */ 2059 size = sizeof(buf) / sizeof(buf[0]); 2060 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size)); 2061 expect_eq_d(lstrlenW(buf), size); 2062 ok(buf[0] == '\\', "NT path should begin with '\\'\n"); 2063 ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n"); 2064 2065 module_name[2] = '\0'; 2066 *device = '\0'; 2067 size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0])); 2068 ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError()); 2069 len = lstrlenW(device); 2070 ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device)); 2071 2072 if (size >= lstrlenW(buf)) 2073 { 2074 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf)); 2075 } 2076 else 2077 { 2078 ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name)); 2079 buf[len] = '\0'; 2080 ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf)); 2081 ok(lstrcmpiW(module_name+3, buf+len+1) == 0, "expected '%s' to match '%s'\n", wine_dbgstr_w(module_name+3), wine_dbgstr_w(buf+len+1)); 2082 } 2083 2084 CloseHandle(hSelf); 2085 } 2086 2087 static void test_Handles(void) 2088 { 2089 HANDLE handle = GetCurrentProcess(); 2090 HANDLE h2, h3; 2091 BOOL ret; 2092 DWORD code; 2093 2094 ok( handle == (HANDLE)~(ULONG_PTR)0 || 2095 handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */, 2096 "invalid current process handle %p\n", handle ); 2097 ret = GetExitCodeProcess( handle, &code ); 2098 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() ); 2099 #ifdef _WIN64 2100 /* truncated handle */ 2101 SetLastError( 0xdeadbeef ); 2102 handle = (HANDLE)((ULONG_PTR)handle & ~0u); 2103 ret = GetExitCodeProcess( handle, &code ); 2104 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle ); 2105 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); 2106 /* sign-extended handle */ 2107 SetLastError( 0xdeadbeef ); 2108 handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle); 2109 ret = GetExitCodeProcess( handle, &code ); 2110 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() ); 2111 /* invalid high-word */ 2112 SetLastError( 0xdeadbeef ); 2113 handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32)); 2114 ret = GetExitCodeProcess( handle, &code ); 2115 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle ); 2116 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); 2117 #endif 2118 2119 handle = GetStdHandle( STD_ERROR_HANDLE ); 2120 ok( handle != 0, "handle %p\n", handle ); 2121 DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &h3, 2122 0, TRUE, DUPLICATE_SAME_ACCESS ); 2123 SetStdHandle( STD_ERROR_HANDLE, h3 ); 2124 CloseHandle( (HANDLE)STD_ERROR_HANDLE ); 2125 h2 = GetStdHandle( STD_ERROR_HANDLE ); 2126 ok( h2 == 0 || 2127 broken( h2 == h3) || /* nt4, w2k */ 2128 broken( h2 == INVALID_HANDLE_VALUE), /* win9x */ 2129 "wrong handle %p/%p\n", h2, h3 ); 2130 SetStdHandle( STD_ERROR_HANDLE, handle ); 2131 } 2132 2133 static void test_IsWow64Process(void) 2134 { 2135 PROCESS_INFORMATION pi; 2136 STARTUPINFOA si; 2137 DWORD ret; 2138 BOOL is_wow64; 2139 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe"; 2140 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe"; 2141 2142 if (!pIsWow64Process) 2143 { 2144 skip("IsWow64Process is not available\n"); 2145 return; 2146 } 2147 2148 memset(&si, 0, sizeof(si)); 2149 si.cb = sizeof(si); 2150 si.dwFlags = STARTF_USESHOWWINDOW; 2151 si.wShowWindow = SW_HIDE; 2152 ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 2153 if (ret) 2154 { 2155 trace("Created process %s\n", cmdline_wow64); 2156 is_wow64 = FALSE; 2157 ret = pIsWow64Process(pi.hProcess, &is_wow64); 2158 ok(ret, "IsWow64Process failed.\n"); 2159 ok(is_wow64, "is_wow64 returned FALSE.\n"); 2160 2161 ret = TerminateProcess(pi.hProcess, 0); 2162 ok(ret, "TerminateProcess error\n"); 2163 2164 CloseHandle(pi.hProcess); 2165 CloseHandle(pi.hThread); 2166 } 2167 2168 memset(&si, 0, sizeof(si)); 2169 si.cb = sizeof(si); 2170 si.dwFlags = STARTF_USESHOWWINDOW; 2171 si.wShowWindow = SW_HIDE; 2172 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 2173 if (ret) 2174 { 2175 trace("Created process %s\n", cmdline); 2176 is_wow64 = TRUE; 2177 ret = pIsWow64Process(pi.hProcess, &is_wow64); 2178 ok(ret, "IsWow64Process failed.\n"); 2179 ok(!is_wow64, "is_wow64 returned TRUE.\n"); 2180 2181 ret = TerminateProcess(pi.hProcess, 0); 2182 ok(ret, "TerminateProcess error\n"); 2183 2184 CloseHandle(pi.hProcess); 2185 CloseHandle(pi.hThread); 2186 } 2187 } 2188 2189 static void test_SystemInfo(void) 2190 { 2191 SYSTEM_INFO si, nsi; 2192 BOOL is_wow64; 2193 2194 if (!pGetNativeSystemInfo) 2195 { 2196 win_skip("GetNativeSystemInfo is not available\n"); 2197 return; 2198 } 2199 2200 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; 2201 2202 GetSystemInfo(&si); 2203 pGetNativeSystemInfo(&nsi); 2204 if (is_wow64) 2205 { 2206 if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) 2207 { 2208 ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64, 2209 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n", 2210 S(U(nsi)).wProcessorArchitecture); 2211 ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664, 2212 "Expected PROCESSOR_AMD_X8664, got %d\n", 2213 nsi.dwProcessorType); 2214 } 2215 } 2216 else 2217 { 2218 ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture, 2219 "Expected no difference for wProcessorArchitecture, got %d and %d\n", 2220 S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture); 2221 ok(si.dwProcessorType == nsi.dwProcessorType, 2222 "Expected no difference for dwProcessorType, got %d and %d\n", 2223 si.dwProcessorType, nsi.dwProcessorType); 2224 } 2225 } 2226 2227 static void test_RegistryQuota(void) 2228 { 2229 BOOL ret; 2230 DWORD max_quota, used_quota; 2231 2232 if (!pGetSystemRegistryQuota) 2233 { 2234 win_skip("GetSystemRegistryQuota is not available\n"); 2235 return; 2236 } 2237 2238 ret = pGetSystemRegistryQuota(NULL, NULL); 2239 ok(ret == TRUE, 2240 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret); 2241 2242 ret = pGetSystemRegistryQuota(&max_quota, NULL); 2243 ok(ret == TRUE, 2244 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret); 2245 2246 ret = pGetSystemRegistryQuota(NULL, &used_quota); 2247 ok(ret == TRUE, 2248 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret); 2249 2250 ret = pGetSystemRegistryQuota(&max_quota, &used_quota); 2251 ok(ret == TRUE, 2252 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret); 2253 } 2254 2255 static void test_TerminateProcess(void) 2256 { 2257 static char cmdline[] = "winver.exe"; 2258 PROCESS_INFORMATION pi; 2259 STARTUPINFOA si; 2260 DWORD ret; 2261 HANDLE dummy, thread; 2262 2263 memset(&si, 0, sizeof(si)); 2264 si.cb = sizeof(si); 2265 SetLastError(0xdeadbeef); 2266 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); 2267 ok(ret, "CreateProcess error %u\n", GetLastError()); 2268 2269 SetLastError(0xdeadbeef); 2270 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret); 2271 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError()); 2272 2273 /* create a not closed thread handle duplicate in the target process */ 2274 SetLastError(0xdeadbeef); 2275 ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy, 2276 0, FALSE, DUPLICATE_SAME_ACCESS); 2277 ok(ret, "DuplicateHandle error %u\n", GetLastError()); 2278 2279 SetLastError(0xdeadbeef); 2280 ret = TerminateThread(thread, 0); 2281 ok(ret, "TerminateThread error %u\n", GetLastError()); 2282 CloseHandle(thread); 2283 2284 SetLastError(0xdeadbeef); 2285 ret = TerminateProcess(pi.hProcess, 0); 2286 ok(ret, "TerminateProcess error %u\n", GetLastError()); 2287 2288 CloseHandle(pi.hProcess); 2289 CloseHandle(pi.hThread); 2290 } 2291 2292 static void test_DuplicateHandle(void) 2293 { 2294 char path[MAX_PATH], file_name[MAX_PATH]; 2295 HANDLE f, fmin, out; 2296 DWORD info; 2297 BOOL r; 2298 2299 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), 2300 GetCurrentProcess(), &out, 0, FALSE, 2301 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 2302 ok(r, "DuplicateHandle error %u\n", GetLastError()); 2303 r = GetHandleInformation(out, &info); 2304 ok(r, "GetHandleInformation error %u\n", GetLastError()); 2305 ok(info == 0, "info = %x\n", info); 2306 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n"); 2307 CloseHandle(out); 2308 2309 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), 2310 GetCurrentProcess(), &out, 0, TRUE, 2311 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 2312 ok(r, "DuplicateHandle error %u\n", GetLastError()); 2313 r = GetHandleInformation(out, &info); 2314 ok(r, "GetHandleInformation error %u\n", GetLastError()); 2315 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info); 2316 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n"); 2317 CloseHandle(out); 2318 2319 GetTempPathA(MAX_PATH, path); 2320 GetTempFileNameA(path, "wt", 0, file_name); 2321 f = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); 2322 if (f == INVALID_HANDLE_VALUE) 2323 { 2324 ok(0, "could not create %s\n", file_name); 2325 return; 2326 } 2327 2328 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 2329 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 2330 ok(r, "DuplicateHandle error %u\n", GetLastError()); 2331 ok(f == out, "f != out\n"); 2332 r = GetHandleInformation(out, &info); 2333 ok(r, "GetHandleInformation error %u\n", GetLastError()); 2334 ok(info == 0, "info = %x\n", info); 2335 2336 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 2337 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 2338 ok(r, "DuplicateHandle error %u\n", GetLastError()); 2339 ok(f == out, "f != out\n"); 2340 r = GetHandleInformation(out, &info); 2341 ok(r, "GetHandleInformation error %u\n", GetLastError()); 2342 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info); 2343 2344 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE); 2345 ok(r, "SetHandleInformation error %u\n", GetLastError()); 2346 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 2347 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 2348 ok(r, "DuplicateHandle error %u\n", GetLastError()); 2349 ok(f != out, "f == out\n"); 2350 r = GetHandleInformation(out, &info); 2351 ok(r, "GetHandleInformation error %u\n", GetLastError()); 2352 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info); 2353 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); 2354 ok(r, "SetHandleInformation error %u\n", GetLastError()); 2355 2356 /* Test if DuplicateHandle allocates first free handle */ 2357 if (f > out) 2358 { 2359 fmin = out; 2360 } 2361 else 2362 { 2363 fmin = f; 2364 f = out; 2365 } 2366 CloseHandle(fmin); 2367 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 2368 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 2369 ok(r, "DuplicateHandle error %u\n", GetLastError()); 2370 ok(f == out, "f != out\n"); 2371 CloseHandle(out); 2372 DeleteFileA(file_name); 2373 2374 f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); 2375 if (!is_console(f)) 2376 { 2377 skip("DuplicateHandle on console handle\n"); 2378 CloseHandle(f); 2379 return; 2380 } 2381 2382 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, 2383 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 2384 ok(r, "DuplicateHandle error %u\n", GetLastError()); 2385 todo_wine ok(f != out, "f == out\n"); 2386 CloseHandle(out); 2387 } 2388 2389 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e) 2390 static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait) 2391 { 2392 LPOVERLAPPED overlapped; 2393 ULONG_PTR value; 2394 DWORD key; 2395 BOOL ret; 2396 2397 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait); 2398 2399 ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError()); 2400 if (ret) 2401 { 2402 ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key); 2403 ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value); 2404 ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped); 2405 } 2406 } 2407 2408 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi) 2409 static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi) 2410 { 2411 BOOL ret; 2412 char buffer[MAX_PATH]; 2413 STARTUPINFOA si = {0}; 2414 2415 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command); 2416 2417 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi); 2418 ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError()); 2419 } 2420 2421 #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__) 2422 static void _test_assigned_proc(int line, HANDLE job, int expected_count, ...) 2423 { 2424 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20]; 2425 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf; 2426 DWORD ret_len, pid; 2427 va_list valist; 2428 int n; 2429 BOOL ret; 2430 2431 memset(buf, 0, sizeof(buf)); 2432 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len); 2433 ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError()); 2434 if (ret) 2435 { 2436 todo_wine_if(expected_count) 2437 ok_(__FILE__, line)(expected_count == pid_list->NumberOfAssignedProcesses, 2438 "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n", 2439 expected_count, pid_list->NumberOfAssignedProcesses); 2440 todo_wine_if(expected_count) 2441 ok_(__FILE__, line)(expected_count == pid_list->NumberOfProcessIdsInList, 2442 "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n", 2443 expected_count, pid_list->NumberOfProcessIdsInList); 2444 2445 va_start(valist, expected_count); 2446 for (n = 0; n < min(expected_count, pid_list->NumberOfProcessIdsInList); ++n) 2447 { 2448 pid = va_arg(valist, DWORD); 2449 ok_(__FILE__, line)(pid == pid_list->ProcessIdList[n], 2450 "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n", 2451 n, pid, pid_list->ProcessIdList[n]); 2452 } 2453 va_end(valist); 2454 } 2455 } 2456 2457 #define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc) 2458 static void _test_accounting(int line, HANDLE job, int total_proc, int active_proc, int terminated_proc) 2459 { 2460 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting; 2461 DWORD ret_len; 2462 BOOL ret; 2463 2464 memset(&basic_accounting, 0, sizeof(basic_accounting)); 2465 ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting, sizeof(basic_accounting), &ret_len); 2466 ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError()); 2467 if (ret) 2468 { 2469 /* Not going to check process times or page faults */ 2470 2471 todo_wine_if(total_proc) 2472 ok_(__FILE__, line)(total_proc == basic_accounting.TotalProcesses, 2473 "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n", 2474 total_proc, basic_accounting.TotalProcesses); 2475 todo_wine_if(active_proc) 2476 ok_(__FILE__, line)(active_proc == basic_accounting.ActiveProcesses, 2477 "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n", 2478 active_proc, basic_accounting.ActiveProcesses); 2479 ok_(__FILE__, line)(terminated_proc == basic_accounting.TotalTerminatedProcesses, 2480 "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n", 2481 terminated_proc, basic_accounting.TotalTerminatedProcesses); 2482 } 2483 } 2484 2485 static void test_IsProcessInJob(void) 2486 { 2487 HANDLE job, job2; 2488 PROCESS_INFORMATION pi; 2489 BOOL ret, out; 2490 DWORD dwret; 2491 2492 if (!pIsProcessInJob) 2493 { 2494 win_skip("IsProcessInJob not available.\n"); 2495 return; 2496 } 2497 2498 job = pCreateJobObjectW(NULL, NULL); 2499 ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); 2500 2501 job2 = pCreateJobObjectW(NULL, NULL); 2502 ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError()); 2503 2504 create_process("wait", &pi); 2505 2506 out = TRUE; 2507 ret = pIsProcessInJob(pi.hProcess, job, &out); 2508 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 2509 ok(!out, "IsProcessInJob returned out=%u\n", out); 2510 test_assigned_proc(job, 0); 2511 test_accounting(job, 0, 0, 0); 2512 2513 out = TRUE; 2514 ret = pIsProcessInJob(pi.hProcess, job2, &out); 2515 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 2516 ok(!out, "IsProcessInJob returned out=%u\n", out); 2517 test_assigned_proc(job2, 0); 2518 test_accounting(job2, 0, 0, 0); 2519 2520 out = TRUE; 2521 ret = pIsProcessInJob(pi.hProcess, NULL, &out); 2522 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 2523 ok(!out, "IsProcessInJob returned out=%u\n", out); 2524 2525 ret = pAssignProcessToJobObject(job, pi.hProcess); 2526 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2527 2528 out = FALSE; 2529 ret = pIsProcessInJob(pi.hProcess, job, &out); 2530 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 2531 ok(out, "IsProcessInJob returned out=%u\n", out); 2532 test_assigned_proc(job, 1, pi.dwProcessId); 2533 test_accounting(job, 1, 1, 0); 2534 2535 out = TRUE; 2536 ret = pIsProcessInJob(pi.hProcess, job2, &out); 2537 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 2538 ok(!out, "IsProcessInJob returned out=%u\n", out); 2539 test_assigned_proc(job2, 0); 2540 test_accounting(job2, 0, 0, 0); 2541 2542 out = FALSE; 2543 ret = pIsProcessInJob(pi.hProcess, NULL, &out); 2544 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 2545 ok(out, "IsProcessInJob returned out=%u\n", out); 2546 2547 TerminateProcess(pi.hProcess, 0); 2548 2549 dwret = WaitForSingleObject(pi.hProcess, 1000); 2550 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2551 2552 out = FALSE; 2553 ret = pIsProcessInJob(pi.hProcess, job, &out); 2554 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 2555 ok(out, "IsProcessInJob returned out=%u\n", out); 2556 test_assigned_proc(job, 0); 2557 test_accounting(job, 1, 0, 0); 2558 2559 CloseHandle(pi.hProcess); 2560 CloseHandle(pi.hThread); 2561 CloseHandle(job); 2562 CloseHandle(job2); 2563 } 2564 2565 static void test_TerminateJobObject(void) 2566 { 2567 HANDLE job; 2568 PROCESS_INFORMATION pi; 2569 BOOL ret; 2570 DWORD dwret; 2571 2572 job = pCreateJobObjectW(NULL, NULL); 2573 ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); 2574 test_assigned_proc(job, 0); 2575 test_accounting(job, 0, 0, 0); 2576 2577 create_process("wait", &pi); 2578 2579 ret = pAssignProcessToJobObject(job, pi.hProcess); 2580 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2581 test_assigned_proc(job, 1, pi.dwProcessId); 2582 test_accounting(job, 1, 1, 0); 2583 2584 ret = pTerminateJobObject(job, 123); 2585 ok(ret, "TerminateJobObject error %u\n", GetLastError()); 2586 2587 dwret = WaitForSingleObject(pi.hProcess, 1000); 2588 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2589 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0); 2590 test_assigned_proc(job, 0); 2591 test_accounting(job, 1, 0, 0); 2592 2593 ret = GetExitCodeProcess(pi.hProcess, &dwret); 2594 ok(ret, "GetExitCodeProcess error %u\n", GetLastError()); 2595 ok(dwret == 123 || broken(dwret == 0) || broken(dwret == 259) /* randomly fails on Win 2000 / XP */, 2596 "wrong exitcode %u\n", dwret); 2597 2598 CloseHandle(pi.hProcess); 2599 CloseHandle(pi.hThread); 2600 2601 /* Test adding an already terminated process to a job object */ 2602 create_process("exit", &pi); 2603 2604 dwret = WaitForSingleObject(pi.hProcess, 1000); 2605 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2606 2607 SetLastError(0xdeadbeef); 2608 ret = pAssignProcessToJobObject(job, pi.hProcess); 2609 ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n"); 2610 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError()); 2611 test_assigned_proc(job, 0); 2612 test_accounting(job, 1, 0, 0); 2613 2614 CloseHandle(pi.hProcess); 2615 CloseHandle(pi.hThread); 2616 2617 CloseHandle(job); 2618 } 2619 2620 static void test_QueryInformationJobObject(void) 2621 { 2622 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4]; 2623 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf; 2624 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info; 2625 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation; 2626 DWORD dwret, ret_len; 2627 PROCESS_INFORMATION pi[2]; 2628 HANDLE job; 2629 BOOL ret; 2630 2631 job = pCreateJobObjectW(NULL, NULL); 2632 ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); 2633 2634 /* Only active processes are returned */ 2635 create_process("exit", &pi[0]); 2636 ret = pAssignProcessToJobObject(job, pi[0].hProcess); 2637 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2638 dwret = WaitForSingleObject(pi[0].hProcess, 1000); 2639 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2640 2641 CloseHandle(pi[0].hProcess); 2642 CloseHandle(pi[0].hThread); 2643 2644 create_process("wait", &pi[0]); 2645 ret = pAssignProcessToJobObject(job, pi[0].hProcess); 2646 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2647 2648 create_process("wait", &pi[1]); 2649 ret = pAssignProcessToJobObject(job, pi[1].hProcess); 2650 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2651 2652 SetLastError(0xdeadbeef); 2653 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, 2654 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len); 2655 ok(!ret, "QueryInformationJobObject expected failure\n"); 2656 expect_eq_d(ERROR_BAD_LENGTH, GetLastError()); 2657 2658 SetLastError(0xdeadbeef); 2659 memset(buf, 0, sizeof(buf)); 2660 pid_list->NumberOfAssignedProcesses = 42; 2661 pid_list->NumberOfProcessIdsInList = 42; 2662 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, 2663 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len); 2664 todo_wine 2665 ok(!ret, "QueryInformationJobObject expected failure\n"); 2666 todo_wine 2667 expect_eq_d(ERROR_MORE_DATA, GetLastError()); 2668 if (ret) 2669 { 2670 todo_wine 2671 expect_eq_d(42, pid_list->NumberOfAssignedProcesses); 2672 todo_wine 2673 expect_eq_d(42, pid_list->NumberOfProcessIdsInList); 2674 } 2675 2676 memset(buf, 0, sizeof(buf)); 2677 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len); 2678 ok(ret, "QueryInformationJobObject error %u\n", GetLastError()); 2679 if(ret) 2680 { 2681 if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */ 2682 win_skip("Number of assigned processes broken on Win 8\n"); 2683 else 2684 { 2685 ULONG_PTR *list = pid_list->ProcessIdList; 2686 2687 todo_wine 2688 ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]), 2689 "QueryInformationJobObject returned ret_len=%u\n", ret_len); 2690 2691 todo_wine 2692 expect_eq_d(2, pid_list->NumberOfAssignedProcesses); 2693 todo_wine 2694 expect_eq_d(2, pid_list->NumberOfProcessIdsInList); 2695 todo_wine 2696 expect_eq_d(pi[0].dwProcessId, list[0]); 2697 todo_wine 2698 expect_eq_d(pi[1].dwProcessId, list[1]); 2699 } 2700 } 2701 2702 /* test JobObjectBasicLimitInformation */ 2703 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info, 2704 sizeof(*basic_limit_info) - 1, &ret_len); 2705 ok(!ret, "QueryInformationJobObject expected failure\n"); 2706 expect_eq_d(ERROR_BAD_LENGTH, GetLastError()); 2707 2708 ret_len = 0xdeadbeef; 2709 memset(basic_limit_info, 0x11, sizeof(*basic_limit_info)); 2710 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info, 2711 sizeof(*basic_limit_info), &ret_len); 2712 ok(ret, "QueryInformationJobObject error %u\n", GetLastError()); 2713 ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len); 2714 expect_eq_d(0, basic_limit_info->LimitFlags); 2715 2716 /* test JobObjectExtendedLimitInformation */ 2717 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info, 2718 sizeof(ext_limit_info) - 1, &ret_len); 2719 ok(!ret, "QueryInformationJobObject expected failure\n"); 2720 expect_eq_d(ERROR_BAD_LENGTH, GetLastError()); 2721 2722 ret_len = 0xdeadbeef; 2723 memset(&ext_limit_info, 0x11, sizeof(ext_limit_info)); 2724 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info, 2725 sizeof(ext_limit_info), &ret_len); 2726 ok(ret, "QueryInformationJobObject error %u\n", GetLastError()); 2727 ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len); 2728 expect_eq_d(0, basic_limit_info->LimitFlags); 2729 2730 TerminateProcess(pi[0].hProcess, 0); 2731 CloseHandle(pi[0].hProcess); 2732 CloseHandle(pi[0].hThread); 2733 2734 TerminateProcess(pi[1].hProcess, 0); 2735 CloseHandle(pi[1].hProcess); 2736 CloseHandle(pi[1].hThread); 2737 2738 CloseHandle(job); 2739 } 2740 2741 static void test_CompletionPort(void) 2742 { 2743 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info; 2744 PROCESS_INFORMATION pi; 2745 HANDLE job, port; 2746 DWORD dwret; 2747 BOOL ret; 2748 2749 job = pCreateJobObjectW(NULL, NULL); 2750 ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); 2751 2752 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); 2753 ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError()); 2754 2755 port_info.CompletionKey = job; 2756 port_info.CompletionPort = port; 2757 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); 2758 ok(ret, "SetInformationJobObject error %u\n", GetLastError()); 2759 2760 create_process("wait", &pi); 2761 2762 ret = pAssignProcessToJobObject(job, pi.hProcess); 2763 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2764 2765 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0); 2766 2767 TerminateProcess(pi.hProcess, 0); 2768 dwret = WaitForSingleObject(pi.hProcess, 1000); 2769 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2770 2771 test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0); 2772 test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100); 2773 2774 CloseHandle(pi.hProcess); 2775 CloseHandle(pi.hThread); 2776 CloseHandle(job); 2777 CloseHandle(port); 2778 } 2779 2780 static void test_KillOnJobClose(void) 2781 { 2782 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info; 2783 PROCESS_INFORMATION pi; 2784 DWORD dwret; 2785 HANDLE job; 2786 BOOL ret; 2787 2788 job = pCreateJobObjectW(NULL, NULL); 2789 ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); 2790 2791 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 2792 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); 2793 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) 2794 { 2795 win_skip("Kill on job close limit not available\n"); 2796 return; 2797 } 2798 ok(ret, "SetInformationJobObject error %u\n", GetLastError()); 2799 test_assigned_proc(job, 0); 2800 test_accounting(job, 0, 0, 0); 2801 2802 create_process("wait", &pi); 2803 2804 ret = pAssignProcessToJobObject(job, pi.hProcess); 2805 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2806 test_assigned_proc(job, 1, pi.dwProcessId); 2807 test_accounting(job, 1, 1, 0); 2808 2809 CloseHandle(job); 2810 2811 dwret = WaitForSingleObject(pi.hProcess, 1000); 2812 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2813 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0); 2814 2815 CloseHandle(pi.hProcess); 2816 CloseHandle(pi.hThread); 2817 } 2818 2819 static void test_WaitForJobObject(void) 2820 { 2821 HANDLE job; 2822 PROCESS_INFORMATION pi; 2823 BOOL ret; 2824 DWORD dwret; 2825 2826 /* test waiting for a job object when the process is killed */ 2827 job = pCreateJobObjectW(NULL, NULL); 2828 ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); 2829 2830 dwret = WaitForSingleObject(job, 100); 2831 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret); 2832 2833 create_process("wait", &pi); 2834 2835 ret = pAssignProcessToJobObject(job, pi.hProcess); 2836 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2837 2838 dwret = WaitForSingleObject(job, 100); 2839 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret); 2840 2841 ret = pTerminateJobObject(job, 123); 2842 ok(ret, "TerminateJobObject error %u\n", GetLastError()); 2843 2844 dwret = WaitForSingleObject(job, 500); 2845 ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT), 2846 "WaitForSingleObject returned %u\n", dwret); 2847 2848 if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */ 2849 { 2850 #ifdef __REACTOS__ 2851 if (!ret) 2852 { 2853 ok(0, "HACK: Killing process to speed up the test\n"); 2854 TerminateProcess(pi.hProcess, 0); 2855 } 2856 #endif 2857 CloseHandle(pi.hProcess); 2858 CloseHandle(pi.hThread); 2859 CloseHandle(job); 2860 win_skip("TerminateJobObject doesn't signal job, skipping tests\n"); 2861 return; 2862 } 2863 2864 /* the object is not reset immediately */ 2865 dwret = WaitForSingleObject(job, 100); 2866 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2867 2868 CloseHandle(pi.hProcess); 2869 CloseHandle(pi.hThread); 2870 2871 /* creating a new process doesn't reset the signalled state */ 2872 create_process("wait", &pi); 2873 2874 ret = pAssignProcessToJobObject(job, pi.hProcess); 2875 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2876 2877 dwret = WaitForSingleObject(job, 100); 2878 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2879 2880 ret = pTerminateJobObject(job, 123); 2881 ok(ret, "TerminateJobObject error %u\n", GetLastError()); 2882 2883 CloseHandle(pi.hProcess); 2884 CloseHandle(pi.hThread); 2885 2886 CloseHandle(job); 2887 2888 /* repeat the test, but this time the process terminates properly */ 2889 job = pCreateJobObjectW(NULL, NULL); 2890 ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); 2891 2892 dwret = WaitForSingleObject(job, 100); 2893 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret); 2894 2895 create_process("exit", &pi); 2896 2897 ret = pAssignProcessToJobObject(job, pi.hProcess); 2898 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2899 2900 dwret = WaitForSingleObject(job, 100); 2901 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret); 2902 2903 CloseHandle(pi.hProcess); 2904 CloseHandle(pi.hThread); 2905 CloseHandle(job); 2906 } 2907 2908 static HANDLE test_AddSelfToJob(void) 2909 { 2910 HANDLE job; 2911 BOOL ret; 2912 2913 job = pCreateJobObjectW(NULL, NULL); 2914 ok(job != NULL, "CreateJobObject error %u\n", GetLastError()); 2915 2916 ret = pAssignProcessToJobObject(job, GetCurrentProcess()); 2917 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); 2918 test_assigned_proc(job, 1, GetCurrentProcessId()); 2919 test_accounting(job, 1, 1, 0); 2920 2921 return job; 2922 } 2923 2924 static void test_jobInheritance(HANDLE job) 2925 { 2926 char buffer[MAX_PATH]; 2927 PROCESS_INFORMATION pi; 2928 STARTUPINFOA si = {0}; 2929 DWORD dwret; 2930 BOOL ret, out; 2931 2932 if (!pIsProcessInJob) 2933 { 2934 win_skip("IsProcessInJob not available.\n"); 2935 return; 2936 } 2937 2938 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit"); 2939 2940 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 2941 ok(ret, "CreateProcessA error %u\n", GetLastError()); 2942 2943 out = FALSE; 2944 ret = pIsProcessInJob(pi.hProcess, job, &out); 2945 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 2946 ok(out, "IsProcessInJob returned out=%u\n", out); 2947 test_assigned_proc(job, 2, GetCurrentProcessId(), pi.dwProcessId); 2948 test_accounting(job, 2, 2, 0); 2949 2950 dwret = WaitForSingleObject(pi.hProcess, 1000); 2951 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2952 2953 CloseHandle(pi.hProcess); 2954 CloseHandle(pi.hThread); 2955 } 2956 2957 static void test_BreakawayOk(HANDLE job) 2958 { 2959 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info; 2960 PROCESS_INFORMATION pi; 2961 STARTUPINFOA si = {0}; 2962 char buffer[MAX_PATH]; 2963 BOOL ret, out; 2964 DWORD dwret; 2965 2966 if (!pIsProcessInJob) 2967 { 2968 win_skip("IsProcessInJob not available.\n"); 2969 return; 2970 } 2971 2972 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit"); 2973 2974 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi); 2975 ok(!ret, "CreateProcessA expected failure\n"); 2976 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError()); 2977 test_assigned_proc(job, 1, GetCurrentProcessId()); 2978 test_accounting(job, 2, 1, 0); 2979 2980 if (ret) 2981 { 2982 TerminateProcess(pi.hProcess, 0); 2983 2984 dwret = WaitForSingleObject(pi.hProcess, 1000); 2985 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 2986 2987 CloseHandle(pi.hProcess); 2988 CloseHandle(pi.hThread); 2989 } 2990 2991 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK; 2992 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); 2993 ok(ret, "SetInformationJobObject error %u\n", GetLastError()); 2994 2995 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi); 2996 ok(ret, "CreateProcessA error %u\n", GetLastError()); 2997 2998 ret = pIsProcessInJob(pi.hProcess, job, &out); 2999 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 3000 ok(!out, "IsProcessInJob returned out=%u\n", out); 3001 test_assigned_proc(job, 1, GetCurrentProcessId()); 3002 test_accounting(job, 2, 1, 0); 3003 3004 dwret = WaitForSingleObject(pi.hProcess, 1000); 3005 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 3006 3007 CloseHandle(pi.hProcess); 3008 CloseHandle(pi.hThread); 3009 3010 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; 3011 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); 3012 ok(ret, "SetInformationJobObject error %u\n", GetLastError()); 3013 3014 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 3015 ok(ret, "CreateProcess error %u\n", GetLastError()); 3016 3017 ret = pIsProcessInJob(pi.hProcess, job, &out); 3018 ok(ret, "IsProcessInJob error %u\n", GetLastError()); 3019 ok(!out, "IsProcessInJob returned out=%u\n", out); 3020 test_assigned_proc(job, 1, GetCurrentProcessId()); 3021 test_accounting(job, 2, 1, 0); 3022 3023 dwret = WaitForSingleObject(pi.hProcess, 1000); 3024 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); 3025 3026 CloseHandle(pi.hProcess); 3027 CloseHandle(pi.hThread); 3028 3029 /* unset breakaway ok */ 3030 limit_info.BasicLimitInformation.LimitFlags = 0; 3031 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info)); 3032 ok(ret, "SetInformationJobObject error %u\n", GetLastError()); 3033 } 3034 3035 static void test_StartupNoConsole(void) 3036 { 3037 #ifndef _WIN64 3038 char buffer[MAX_PATH]; 3039 STARTUPINFOA startup; 3040 PROCESS_INFORMATION info; 3041 3042 memset(&startup, 0, sizeof(startup)); 3043 startup.cb = sizeof(startup); 3044 startup.dwFlags = STARTF_USESHOWWINDOW; 3045 startup.wShowWindow = SW_SHOWNORMAL; 3046 get_file_name(resfile); 3047 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 3048 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, 3049 &info), "CreateProcess\n"); 3050 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 3051 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 3052 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE); 3053 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE); 3054 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE); 3055 okChildInt("TEB", "hStdInput", 0); 3056 okChildInt("TEB", "hStdOutput", 0); 3057 okChildInt("TEB", "hStdError", 0); 3058 release_memory(); 3059 DeleteFileA(resfile); 3060 #endif 3061 } 3062 3063 static void test_DetachConsoleHandles(void) 3064 { 3065 #ifndef _WIN64 3066 char buffer[MAX_PATH]; 3067 STARTUPINFOA startup; 3068 PROCESS_INFORMATION info; 3069 UINT result; 3070 3071 memset(&startup, 0, sizeof(startup)); 3072 startup.cb = sizeof(startup); 3073 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; 3074 startup.wShowWindow = SW_SHOWNORMAL; 3075 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 3076 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 3077 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE); 3078 get_file_name(resfile); 3079 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 3080 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, 3081 &info), "CreateProcess\n"); 3082 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 3083 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 3084 3085 result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile); 3086 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); 3087 result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile); 3088 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); 3089 result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile); 3090 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); 3091 result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile); 3092 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); 3093 result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile); 3094 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); 3095 result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile); 3096 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); 3097 3098 release_memory(); 3099 DeleteFileA(resfile); 3100 #endif 3101 } 3102 3103 #if defined(__i386__) || defined(__x86_64__) 3104 static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi, 3105 IMAGE_NT_HEADERS *nt_header) 3106 { 3107 IMAGE_DOS_HEADER dos_header; 3108 3109 if (!ReadProcessMemory(process_handle, mbi->BaseAddress, &dos_header, sizeof(dos_header), NULL)) 3110 return FALSE; 3111 3112 if ((dos_header.e_magic != IMAGE_DOS_SIGNATURE) || 3113 ((ULONG)dos_header.e_lfanew > mbi->RegionSize) || 3114 (dos_header.e_lfanew < sizeof(dos_header))) 3115 return FALSE; 3116 3117 if (!ReadProcessMemory(process_handle, (char *)mbi->BaseAddress + dos_header.e_lfanew, 3118 nt_header, sizeof(*nt_header), NULL)) 3119 return FALSE; 3120 3121 return (nt_header->Signature == IMAGE_NT_SIGNATURE); 3122 } 3123 3124 static PVOID get_process_exe(HANDLE process_handle, IMAGE_NT_HEADERS *nt_header) 3125 { 3126 PVOID exe_base, address; 3127 MEMORY_BASIC_INFORMATION mbi; 3128 3129 /* Find the EXE base in the new process */ 3130 exe_base = NULL; 3131 for (address = NULL ; 3132 VirtualQueryEx(process_handle, address, &mbi, sizeof(mbi)) ; 3133 address = (char *)mbi.BaseAddress + mbi.RegionSize) { 3134 if ((mbi.Type == SEC_IMAGE) && 3135 read_nt_header(process_handle, &mbi, nt_header) && 3136 !(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) { 3137 exe_base = mbi.BaseAddress; 3138 break; 3139 } 3140 } 3141 3142 return exe_base; 3143 } 3144 3145 static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE_NT_HEADERS *nt_header) 3146 { 3147 BOOL ret; 3148 IMAGE_IMPORT_DESCRIPTOR iid; 3149 ULONG_PTR orig_iat_entry_value, iat_entry_value; 3150 3151 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, "Import table VA is zero\n"); 3152 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, "Import table Size is zero\n"); 3153 3154 if (!nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress || 3155 !nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) 3156 return FALSE; 3157 3158 /* Read the first IID */ 3159 ret = ReadProcessMemory(process_handle, 3160 (char *)module_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, 3161 &iid, sizeof(iid), NULL); 3162 ok(ret, "Failed to read remote module IID (%d)\n", GetLastError()); 3163 3164 /* Validate the IID is present and not a bound import, and that we have 3165 an OriginalFirstThunk to compare with */ 3166 ok(iid.Name, "Module first IID does not have a Name\n"); 3167 ok(iid.FirstThunk, "Module first IID does not have a FirstThunk\n"); 3168 ok(!iid.TimeDateStamp, "Module first IID is a bound import (UNSUPPORTED for current test)\n"); 3169 ok(iid.OriginalFirstThunk, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n"); 3170 3171 /* Read a single IAT entry from the FirstThunk */ 3172 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.FirstThunk, 3173 &iat_entry_value, sizeof(iat_entry_value), NULL); 3174 ok(ret, "Failed to read IAT entry from FirstThunk (%d)\n", GetLastError()); 3175 ok(iat_entry_value, "IAT entry in FirstThunk is NULL\n"); 3176 3177 /* Read a single IAT entry from the OriginalFirstThunk */ 3178 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.OriginalFirstThunk, 3179 &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL); 3180 ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%d)\n", GetLastError()); 3181 ok(orig_iat_entry_value, "IAT entry in OriginalFirstThunk is NULL\n"); 3182 3183 return iat_entry_value != orig_iat_entry_value; 3184 } 3185 3186 static void test_SuspendProcessNewThread(void) 3187 { 3188 BOOL ret; 3189 STARTUPINFOA si = {0}; 3190 PROCESS_INFORMATION pi = {0}; 3191 PVOID exe_base, exit_thread_ptr; 3192 IMAGE_NT_HEADERS nt_header; 3193 HANDLE thread_handle = NULL; 3194 DWORD dret, exit_code = 0; 3195 CONTEXT ctx; 3196 3197 exit_thread_ptr = GetProcAddress(hkernel32, "ExitThread"); 3198 ok(exit_thread_ptr != NULL, "GetProcAddress ExitThread failed\n"); 3199 3200 si.cb = sizeof(si); 3201 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); 3202 ok(ret, "Failed to create process (%d)\n", GetLastError()); 3203 3204 exe_base = get_process_exe(pi.hProcess, &nt_header); 3205 ok(exe_base != NULL, "Could not find EXE in remote process\n"); 3206 3207 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header); 3208 ok(!ret, "IAT entry resolved prematurely\n"); 3209 3210 thread_handle = CreateRemoteThread(pi.hProcess, NULL, 0, 3211 (LPTHREAD_START_ROUTINE)exit_thread_ptr, 3212 (PVOID)(ULONG_PTR)0x1234, CREATE_SUSPENDED, NULL); 3213 ok(thread_handle != NULL, "Could not create remote thread (%d)\n", GetLastError()); 3214 3215 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header); 3216 ok(!ret, "IAT entry resolved prematurely\n"); 3217 3218 ctx.ContextFlags = CONTEXT_ALL; 3219 ret = GetThreadContext( thread_handle, &ctx ); 3220 ok( ret, "Failed retrieving remote thread context (%d)\n", GetLastError() ); 3221 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags ); 3222 #ifdef __x86_64__ 3223 ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax ); 3224 ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx ); 3225 ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %lx/%p\n", ctx.Rcx, exit_thread_ptr ); 3226 ok( ctx.Rdx == 0x1234, "wrong rdx %lx\n", ctx.Rdx ); 3227 ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi ); 3228 ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi ); 3229 ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp ); 3230 ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 ); 3231 ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 ); 3232 ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 ); 3233 ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 ); 3234 ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 ); 3235 ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 ); 3236 ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 ); 3237 ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 ); 3238 ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp ); 3239 ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags ); 3240 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr ); 3241 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord ); 3242 #else 3243 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp ); 3244 if (!ctx.Ebp) /* winxp is completely different */ 3245 { 3246 ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx ); 3247 ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx ); 3248 ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi ); 3249 ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi ); 3250 } 3251 ok( ctx.Eax == (ULONG_PTR)exit_thread_ptr, "wrong eax %08x/%p\n", ctx.Eax, exit_thread_ptr ); 3252 ok( ctx.Ebx == 0x1234, "wrong ebx %08x\n", ctx.Ebx ); 3253 ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */ 3254 "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp ); 3255 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags ); 3256 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord ); 3257 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters ); 3258 #endif 3259 3260 ResumeThread( thread_handle ); 3261 dret = WaitForSingleObject(thread_handle, 60000); 3262 ok(dret == WAIT_OBJECT_0, "Waiting for remote thread failed (%d)\n", GetLastError()); 3263 ret = GetExitCodeThread(thread_handle, &exit_code); 3264 ok(ret, "Failed to retrieve remote thread exit code (%d)\n", GetLastError()); 3265 ok(exit_code == 0x1234, "Invalid remote thread exit code\n"); 3266 3267 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header); 3268 ok(ret, "EXE IAT entry not resolved\n"); 3269 3270 if (thread_handle) 3271 CloseHandle(thread_handle); 3272 3273 TerminateProcess(pi.hProcess, 0); 3274 WaitForSingleObject(pi.hProcess, 10000); 3275 CloseHandle(pi.hProcess); 3276 CloseHandle(pi.hThread); 3277 } 3278 3279 static void test_SuspendProcessState(void) 3280 { 3281 struct pipe_params 3282 { 3283 ULONG pipe_write_buf; 3284 ULONG pipe_read_buf; 3285 ULONG bytes_returned; 3286 CHAR pipe_name[MAX_PATH]; 3287 }; 3288 3289 #ifdef __x86_64__ 3290 struct remote_rop_chain 3291 { 3292 void *exit_process_ptr; 3293 ULONG_PTR home_rcx; 3294 ULONG_PTR home_rdx; 3295 ULONG_PTR home_r8; 3296 ULONG_PTR home_r9; 3297 ULONG_PTR pipe_read_buf_size; 3298 ULONG_PTR bytes_returned; 3299 ULONG_PTR timeout; 3300 }; 3301 #else 3302 struct remote_rop_chain 3303 { 3304 void *exit_process_ptr; 3305 ULONG_PTR pipe_name; 3306 ULONG_PTR pipe_write_buf; 3307 ULONG_PTR pipe_write_buf_size; 3308 ULONG_PTR pipe_read_buf; 3309 ULONG_PTR pipe_read_buf_size; 3310 ULONG_PTR bytes_returned; 3311 ULONG_PTR timeout; 3312 void *unreached_ret; 3313 ULONG_PTR exit_code; 3314 }; 3315 #endif 3316 3317 static const char pipe_name[] = "\\\\.\\pipe\\TestPipe"; 3318 static const ULONG pipe_write_magic = 0x454e4957; 3319 STARTUPINFOA si = {0}; 3320 PROCESS_INFORMATION pi = {0}; 3321 PVOID exe_base, remote_pipe_params, exit_process_ptr, 3322 call_named_pipe_a; 3323 IMAGE_NT_HEADERS nt_header; 3324 struct pipe_params pipe_params; 3325 struct remote_rop_chain rop_chain; 3326 CONTEXT ctx; 3327 HANDLE server_pipe_handle; 3328 BOOL pipe_connected; 3329 ULONG pipe_magic, numb; 3330 BOOL ret; 3331 void *entry_ptr, *peb_ptr; 3332 PEB child_peb; 3333 3334 exit_process_ptr = GetProcAddress(hkernel32, "ExitProcess"); 3335 ok(exit_process_ptr != NULL, "GetProcAddress ExitProcess failed\n"); 3336 3337 call_named_pipe_a = GetProcAddress(hkernel32, "CallNamedPipeA"); 3338 ok(call_named_pipe_a != NULL, "GetProcAddress CallNamedPipeA failed\n"); 3339 3340 si.cb = sizeof(si); 3341 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); 3342 ok(ret, "Failed to create process (%d)\n", GetLastError()); 3343 3344 exe_base = get_process_exe(pi.hProcess, &nt_header); 3345 /* Make sure we found the EXE in the new process */ 3346 ok(exe_base != NULL, "Could not find EXE in remote process\n"); 3347 3348 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header); 3349 ok(!ret, "IAT entry resolved prematurely\n"); 3350 3351 server_pipe_handle = CreateNamedPipeA(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH, 3352 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0x20000, 0x20000, 3353 0, NULL); 3354 ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%d)\n", GetLastError()); 3355 3356 /* Set up the remote process environment */ 3357 ctx.ContextFlags = CONTEXT_ALL; 3358 ret = GetThreadContext(pi.hThread, &ctx); 3359 ok(ret, "Failed retrieving remote thread context (%d)\n", GetLastError()); 3360 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags ); 3361 3362 remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE); 3363 ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%d)\n", GetLastError()); 3364 3365 pipe_params.pipe_write_buf = pipe_write_magic; 3366 pipe_params.pipe_read_buf = 0; 3367 pipe_params.bytes_returned = 0; 3368 strcpy(pipe_params.pipe_name, pipe_name); 3369 3370 ret = WriteProcessMemory(pi.hProcess, remote_pipe_params, 3371 &pipe_params, sizeof(pipe_params), NULL); 3372 ok(ret, "Failed to write to remote process memory (%d)\n", GetLastError()); 3373 3374 #ifdef __x86_64__ 3375 ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax ); 3376 ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx ); 3377 ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi ); 3378 ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi ); 3379 ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp ); 3380 ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 ); 3381 ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 ); 3382 ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 ); 3383 ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 ); 3384 ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 ); 3385 ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 ); 3386 ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 ); 3387 ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 ); 3388 ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp ); 3389 ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags ); 3390 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr ); 3391 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord ); 3392 entry_ptr = (void *)ctx.Rcx; 3393 peb_ptr = (void *)ctx.Rdx; 3394 3395 rop_chain.exit_process_ptr = exit_process_ptr; 3396 ctx.Rcx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name); 3397 ctx.Rdx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf); 3398 ctx.R8 = sizeof(pipe_params.pipe_write_buf); 3399 ctx.R9 = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf); 3400 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf); 3401 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned); 3402 rop_chain.timeout = 10000; 3403 3404 ctx.Rip = (ULONG_PTR)call_named_pipe_a; 3405 ctx.Rsp -= sizeof(rop_chain); 3406 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL); 3407 ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError()); 3408 #else 3409 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp ); 3410 if (!ctx.Ebp) /* winxp is completely different */ 3411 { 3412 ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx ); 3413 ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx ); 3414 ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi ); 3415 ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi ); 3416 } 3417 ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */ 3418 "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp ); 3419 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags ); 3420 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord ); 3421 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters ); 3422 entry_ptr = (void *)ctx.Eax; 3423 peb_ptr = (void *)ctx.Ebx; 3424 3425 rop_chain.exit_process_ptr = exit_process_ptr; 3426 rop_chain.pipe_name = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name); 3427 rop_chain.pipe_write_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf); 3428 rop_chain.pipe_write_buf_size = sizeof(pipe_params.pipe_write_buf); 3429 rop_chain.pipe_read_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf); 3430 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf); 3431 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned); 3432 rop_chain.timeout = 10000; 3433 rop_chain.exit_code = 0; 3434 3435 ctx.Eip = (ULONG_PTR)call_named_pipe_a; 3436 ctx.Esp -= sizeof(rop_chain); 3437 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Esp, &rop_chain, sizeof(rop_chain), NULL); 3438 ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError()); 3439 #endif 3440 3441 ret = ReadProcessMemory( pi.hProcess, peb_ptr, &child_peb, sizeof(child_peb), NULL ); 3442 ros_skip_flaky 3443 ok( ret, "Failed to read PEB (%u)\n", GetLastError() ); 3444 ros_skip_flaky 3445 ok( child_peb.ImageBaseAddress == exe_base, "wrong base %p/%p\n", 3446 child_peb.ImageBaseAddress, exe_base ); 3447 ok( entry_ptr == (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint, 3448 "wrong entry point %p/%p\n", entry_ptr, 3449 (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint ); 3450 3451 ret = SetThreadContext(pi.hThread, &ctx); 3452 ok(ret, "Failed to set remote thread context (%d)\n", GetLastError()); 3453 3454 ResumeThread(pi.hThread); 3455 3456 pipe_connected = ConnectNamedPipe(server_pipe_handle, NULL) || (GetLastError() == ERROR_PIPE_CONNECTED); 3457 ok(pipe_connected, "Pipe did not connect\n"); 3458 3459 ret = ReadFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL); 3460 ok(ret, "Failed to read buffer from pipe (%d)\n", GetLastError()); 3461 3462 ok(pipe_magic == pipe_write_magic, "Did not get the correct magic from the remote process\n"); 3463 3464 /* Validate the Imports, at this point the thread in the new process should have 3465 initialized the EXE module imports and call each dll DllMain notifying it on 3466 the new thread in the process. */ 3467 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header); 3468 ok(ret, "EXE IAT is not resolved\n"); 3469 3470 ret = WriteFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL); 3471 ok(ret, "Failed to write the magic back to the pipe (%d)\n", GetLastError()); 3472 3473 CloseHandle(server_pipe_handle); 3474 TerminateProcess(pi.hProcess, 0); 3475 WaitForSingleObject(pi.hProcess, 10000); 3476 CloseHandle(pi.hProcess); 3477 CloseHandle(pi.hThread); 3478 } 3479 #else 3480 static void test_SuspendProcessNewThread(void) 3481 { 3482 } 3483 static void test_SuspendProcessState(void) 3484 { 3485 } 3486 #endif 3487 3488 static void test_DetachStdHandles(void) 3489 { 3490 #ifndef _WIN64 3491 char buffer[MAX_PATH], tempfile[MAX_PATH]; 3492 STARTUPINFOA startup; 3493 PROCESS_INFORMATION info; 3494 HANDLE hstdin, hstdout, hstderr, htemp; 3495 BOOL res; 3496 3497 hstdin = GetStdHandle(STD_INPUT_HANDLE); 3498 hstdout = GetStdHandle(STD_OUTPUT_HANDLE); 3499 hstderr = GetStdHandle(STD_ERROR_HANDLE); 3500 3501 get_file_name(tempfile); 3502 htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); 3503 ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n"); 3504 3505 memset(&startup, 0, sizeof(startup)); 3506 startup.cb = sizeof(startup); 3507 startup.dwFlags = STARTF_USESHOWWINDOW; 3508 startup.wShowWindow = SW_SHOWNORMAL; 3509 get_file_name(resfile); 3510 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile); 3511 3512 SetStdHandle(STD_INPUT_HANDLE, htemp); 3513 SetStdHandle(STD_OUTPUT_HANDLE, htemp); 3514 SetStdHandle(STD_ERROR_HANDLE, htemp); 3515 3516 res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, 3517 &info); 3518 3519 SetStdHandle(STD_INPUT_HANDLE, hstdin); 3520 SetStdHandle(STD_OUTPUT_HANDLE, hstdout); 3521 SetStdHandle(STD_ERROR_HANDLE, hstderr); 3522 3523 ok(res, "CreateProcess failed\n"); 3524 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); 3525 WritePrivateProfileStringA(NULL, NULL, NULL, resfile); 3526 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE); 3527 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE); 3528 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE); 3529 okChildInt("TEB", "hStdInput", 0); 3530 okChildInt("TEB", "hStdOutput", 0); 3531 okChildInt("TEB", "hStdError", 0); 3532 release_memory(); 3533 DeleteFileA(resfile); 3534 3535 CloseHandle(htemp); 3536 DeleteFileA(tempfile); 3537 #endif 3538 } 3539 3540 static void test_GetNumaProcessorNode(void) 3541 { 3542 SYSTEM_INFO si; 3543 UCHAR node; 3544 BOOL ret; 3545 int i; 3546 3547 if (!pGetNumaProcessorNode) 3548 { 3549 win_skip("GetNumaProcessorNode is missing\n"); 3550 return; 3551 } 3552 3553 GetSystemInfo(&si); 3554 for (i = 0; i < 256; i++) 3555 { 3556 SetLastError(0xdeadbeef); 3557 node = (i < si.dwNumberOfProcessors) ? 0xFF : 0xAA; 3558 ret = pGetNumaProcessorNode(i, &node); 3559 if (i < si.dwNumberOfProcessors) 3560 { 3561 ok(ret, "GetNumaProcessorNode returned FALSE for processor %d\n", i); 3562 ok(node != 0xFF, "expected node != 0xFF, but got 0xFF\n"); 3563 } 3564 else 3565 { 3566 ok(!ret, "GetNumaProcessorNode returned TRUE for processor %d\n", i); 3567 ok(node == 0xFF || broken(node == 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node); 3568 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); 3569 } 3570 } 3571 } 3572 3573 static void test_session_info(void) 3574 { 3575 DWORD session_id, active_session; 3576 BOOL r; 3577 3578 if (!pProcessIdToSessionId) 3579 { 3580 win_skip("ProcessIdToSessionId is missing\n"); 3581 return; 3582 } 3583 3584 r = pProcessIdToSessionId(GetCurrentProcessId(), &session_id); 3585 ok(r, "ProcessIdToSessionId failed: %u\n", GetLastError()); 3586 trace("session_id = %x\n", session_id); 3587 3588 active_session = pWTSGetActiveConsoleSessionId(); 3589 trace("active_session = %x\n", active_session); 3590 } 3591 3592 static void test_process_info(void) 3593 { 3594 char buf[4096]; 3595 static const ULONG info_size[] = 3596 { 3597 sizeof(PROCESS_BASIC_INFORMATION) /* ProcessBasicInformation */, 3598 sizeof(QUOTA_LIMITS) /* ProcessQuotaLimits */, 3599 sizeof(IO_COUNTERS) /* ProcessIoCounters */, 3600 sizeof(VM_COUNTERS) /* ProcessVmCounters */, 3601 sizeof(KERNEL_USER_TIMES) /* ProcessTimes */, 3602 sizeof(ULONG) /* ProcessBasePriority */, 3603 sizeof(ULONG) /* ProcessRaisePriority */, 3604 sizeof(HANDLE) /* ProcessDebugPort */, 3605 sizeof(HANDLE) /* ProcessExceptionPort */, 3606 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */, 3607 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */, 3608 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */, 3609 sizeof(ULONG) /* ProcessDefaultHardErrorMode */, 3610 0 /* ProcessIoPortHandlers: kernel-mode only */, 3611 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */, 3612 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */, 3613 sizeof(ULONG) /* ProcessUserModeIOPL */, 3614 sizeof(BOOLEAN) /* ProcessEnableAlignmentFaultFixup */, 3615 sizeof(PROCESS_PRIORITY_CLASS) /* ProcessPriorityClass */, 3616 sizeof(ULONG) /* ProcessWx86Information */, 3617 sizeof(ULONG) /* ProcessHandleCount */, 3618 sizeof(ULONG_PTR) /* ProcessAffinityMask */, 3619 sizeof(ULONG) /* ProcessPriorityBoost */, 3620 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */, 3621 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */, 3622 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */, 3623 sizeof(ULONG_PTR) /* ProcessWow64Information */, 3624 sizeof(buf) /* ProcessImageFileName */, 3625 sizeof(ULONG) /* ProcessLUIDDeviceMapsEnabled */, 3626 sizeof(ULONG) /* ProcessBreakOnTermination */, 3627 sizeof(HANDLE) /* ProcessDebugObjectHandle */, 3628 sizeof(ULONG) /* ProcessDebugFlags */, 3629 sizeof(buf) /* ProcessHandleTracing */, 3630 sizeof(ULONG) /* ProcessIoPriority */, 3631 sizeof(ULONG) /* ProcessExecuteFlags */, 3632 0 /* FIXME: sizeof(?) ProcessTlsInformation */, 3633 0 /* FIXME: sizeof(?) ProcessCookie */, 3634 sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */, 3635 0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */, 3636 sizeof(ULONG) /* ProcessPagePriority */, 3637 40 /* ProcessInstrumentationCallback */, 3638 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */, 3639 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */, 3640 sizeof(buf) /* ProcessImageFileNameWin32 */, 3641 sizeof(HANDLE) /* ProcessImageFileMapping */, 3642 0 /* FIXME: sizeof(PROCESS_AFFINITY_UPDATE_MODE) ProcessAffinityUpdateMode */, 3643 0 /* FIXME: sizeof(PROCESS_MEMORY_ALLOCATION_MODE) ProcessMemoryAllocationMode */, 3644 sizeof(USHORT) /* ProcessGroupInformation */, 3645 sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */, 3646 sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */, 3647 0 /* FIXME: sizeof(PROCESS_WINDOW_INFORMATION) ProcessWindowInformation */, 3648 #if 0 /* FIXME: Add remaining classes */ 3649 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */, 3650 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */, 3651 sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */, 3652 sizeof(?) /* ProcessHandleCheckingMode */, 3653 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION) /* ProcessKeepAliveCount */, 3654 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION) /* ProcessRevokeFileHandles */, 3655 sizeof(PROCESS_WORKING_SET_CONTROL) /* ProcessWorkingSetControl */, 3656 sizeof(?) /* ProcessHandleTable */, 3657 sizeof(?) /* ProcessCheckStackExtentsMode */, 3658 sizeof(buf) /* ProcessCommandLineInformation */, 3659 sizeof(PS_PROTECTION) /* ProcessProtectionInformation */, 3660 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO) /* ProcessMemoryExhaustion */, 3661 sizeof(PROCESS_FAULT_INFORMATION) /* ProcessFaultInformation */, 3662 sizeof(PROCESS_TELEMETRY_ID_INFORMATION) /* ProcessTelemetryIdInformation */, 3663 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION) /* ProcessCommitReleaseInformation */, 3664 sizeof(?) /* ProcessDefaultCpuSetsInformation */, 3665 sizeof(?) /* ProcessAllowedCpuSetsInformation */, 3666 0 /* ProcessReserved1Information */, 3667 0 /* ProcessReserved2Information */, 3668 sizeof(?) /* ProcessSubsystemProcess */, 3669 sizeof(PROCESS_JOB_MEMORY_INFO) /* ProcessJobMemoryInformation */, 3670 #endif 3671 }; 3672 HANDLE hproc; 3673 ULONG i, status, ret_len, size; 3674 3675 if (!pNtQueryInformationProcess) 3676 { 3677 win_skip("NtQueryInformationProcess is not available on this platform\n"); 3678 return; 3679 } 3680 3681 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId()); 3682 if (!hproc) 3683 { 3684 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n"); 3685 return; 3686 } 3687 3688 for (i = 0; i < MaxProcessInfoClass; i++) 3689 { 3690 size = info_size[i]; 3691 if (!size) size = sizeof(buf); 3692 ret_len = 0; 3693 status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len); 3694 if (status == STATUS_NOT_IMPLEMENTED) continue; 3695 if (status == STATUS_INVALID_INFO_CLASS) continue; 3696 if (status == STATUS_INFO_LENGTH_MISMATCH) continue; 3697 3698 switch (i) 3699 { 3700 case ProcessBasicInformation: 3701 case ProcessQuotaLimits: 3702 case ProcessTimes: 3703 case ProcessPriorityClass: 3704 case ProcessPriorityBoost: 3705 case ProcessLUIDDeviceMapsEnabled: 3706 case 33 /* ProcessIoPriority */: 3707 case ProcessIoCounters: 3708 case ProcessVmCounters: 3709 case ProcessWow64Information: 3710 case ProcessDefaultHardErrorMode: 3711 case ProcessHandleCount: 3712 case ProcessImageFileName: 3713 case ProcessImageInformation: 3714 case ProcessPagePriority: 3715 case ProcessImageFileNameWin32: 3716 ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len); 3717 break; 3718 3719 case ProcessAffinityMask: 3720 case ProcessBreakOnTermination: 3721 case ProcessGroupInformation: 3722 case ProcessConsoleHostProcess: 3723 ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */, 3724 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len); 3725 break; 3726 3727 case ProcessDebugObjectHandle: 3728 ok(status == STATUS_ACCESS_DENIED || status == STATUS_PORT_NOT_SET, 3729 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len); 3730 break; 3731 3732 case ProcessExecuteFlags: 3733 case ProcessDebugPort: 3734 case ProcessDebugFlags: 3735 case ProcessCookie: 3736 todo_wine 3737 ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len); 3738 break; 3739 3740 default: 3741 ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len); 3742 break; 3743 } 3744 } 3745 3746 CloseHandle(hproc); 3747 } 3748 3749 static void test_GetLogicalProcessorInformationEx(void) 3750 { 3751 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info; 3752 DWORD len; 3753 BOOL ret; 3754 3755 if (!pGetLogicalProcessorInformationEx) 3756 { 3757 win_skip("GetLogicalProcessorInformationEx() is not supported\n"); 3758 return; 3759 } 3760 3761 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, NULL); 3762 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError()); 3763 3764 len = 0; 3765 ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len); 3766 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError()); 3767 ok(len > 0, "got %u\n", len); 3768 3769 len = 0; 3770 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len); 3771 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError()); 3772 ok(len > 0, "got %u\n", len); 3773 3774 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); 3775 ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len); 3776 ok(ret, "got %d, error %d\n", ret, GetLastError()); 3777 ok(info->Size > 0, "got %u\n", info->Size); 3778 HeapFree(GetProcessHeap(), 0, info); 3779 } 3780 3781 static void test_largepages(void) 3782 { 3783 SIZE_T size; 3784 3785 if (!pGetLargePageMinimum) { 3786 skip("No GetLargePageMinimum support.\n"); 3787 return; 3788 } 3789 size = pGetLargePageMinimum(); 3790 3791 ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size); 3792 } 3793 3794 struct proc_thread_attr 3795 { 3796 DWORD_PTR attr; 3797 SIZE_T size; 3798 void *value; 3799 }; 3800 3801 struct _PROC_THREAD_ATTRIBUTE_LIST 3802 { 3803 DWORD mask; /* bitmask of items in list */ 3804 DWORD size; /* max number of items in list */ 3805 DWORD count; /* number of items in list */ 3806 DWORD pad; 3807 DWORD_PTR unk; 3808 struct proc_thread_attr attrs[10]; 3809 }; 3810 3811 static void test_ProcThreadAttributeList(void) 3812 { 3813 BOOL ret; 3814 SIZE_T size, needed; 3815 int i; 3816 struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list; 3817 HANDLE handles[4]; 3818 3819 if (!pInitializeProcThreadAttributeList) 3820 { 3821 win_skip("No support for ProcThreadAttributeList\n"); 3822 return; 3823 } 3824 3825 for (i = 0; i <= 10; i++) 3826 { 3827 needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[i]); 3828 ret = pInitializeProcThreadAttributeList(NULL, i, 0, &size); 3829 ok(!ret, "got %d\n", ret); 3830 if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */ 3831 break; 3832 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError()); 3833 ok(size == needed, "%d: got %ld expect %ld\n", i, size, needed); 3834 3835 memset(&list, 0xcc, sizeof(list)); 3836 ret = pInitializeProcThreadAttributeList(&list, i, 0, &size); 3837 ok(ret, "got %d\n", ret); 3838 ok(list.mask == 0, "%d: got %08x\n", i, list.mask); 3839 ok(list.size == i, "%d: got %08x\n", i, list.size); 3840 ok(list.count == 0, "%d: got %08x\n", i, list.count); 3841 ok(list.unk == 0, "%d: got %08lx\n", i, list.unk); 3842 } 3843 3844 memset(handles, 0, sizeof(handles)); 3845 memset(&expect_list, 0xcc, sizeof(expect_list)); 3846 expect_list.mask = 0; 3847 expect_list.size = i - 1; 3848 expect_list.count = 0; 3849 expect_list.unk = 0; 3850 3851 ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL); 3852 ok(!ret, "got %d\n", ret); 3853 ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %d\n", GetLastError()); 3854 3855 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL); 3856 ok(!ret, "got %d\n", ret); 3857 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError()); 3858 3859 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL); 3860 ok(!ret, "got %d\n", ret); 3861 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError()); 3862 3863 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL); 3864 ok(ret, "got %d\n", ret); 3865 3866 expect_list.mask |= 1 << ProcThreadAttributeParentProcess; 3867 expect_list.attrs[0].attr = PROC_THREAD_ATTRIBUTE_PARENT_PROCESS; 3868 expect_list.attrs[0].size = sizeof(handles[0]); 3869 expect_list.attrs[0].value = handles; 3870 expect_list.count++; 3871 3872 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL); 3873 ok(!ret, "got %d\n", ret); 3874 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError()); 3875 3876 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL); 3877 ok(!ret, "got %d\n", ret); 3878 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError()); 3879 3880 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL); 3881 ok(ret, "got %d\n", ret); 3882 3883 expect_list.mask |= 1 << ProcThreadAttributeHandleList; 3884 expect_list.attrs[1].attr = PROC_THREAD_ATTRIBUTE_HANDLE_LIST; 3885 expect_list.attrs[1].size = sizeof(handles); 3886 expect_list.attrs[1].value = handles; 3887 expect_list.count++; 3888 3889 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL); 3890 ok(!ret, "got %d\n", ret); 3891 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError()); 3892 3893 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL); 3894 ok(ret || GetLastError() == ERROR_NOT_SUPPORTED, "got %d gle %d\n", ret, GetLastError()); 3895 3896 if (ret) 3897 { 3898 expect_list.mask |= 1 << ProcThreadAttributeIdealProcessor; 3899 expect_list.attrs[2].attr = PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR; 3900 expect_list.attrs[2].size = sizeof(PROCESSOR_NUMBER); 3901 expect_list.attrs[2].value = handles; 3902 expect_list.count++; 3903 } 3904 3905 ok(!memcmp(&list, &expect_list, size), "mismatch\n"); 3906 3907 pDeleteProcThreadAttributeList(&list); 3908 } 3909 3910 static void test_GetActiveProcessorCount(void) 3911 { 3912 DWORD count; 3913 3914 if (!pGetActiveProcessorCount) 3915 { 3916 win_skip("GetActiveProcessorCount not available, skipping test\n"); 3917 return; 3918 } 3919 3920 count = pGetActiveProcessorCount(0); 3921 ok(count, "GetActiveProcessorCount failed, error %u\n", GetLastError()); 3922 3923 /* Test would fail on systems with more than 6400 processors */ 3924 SetLastError(0xdeadbeef); 3925 count = pGetActiveProcessorCount(101); 3926 ok(count == 0, "Expeced GetActiveProcessorCount to fail\n"); 3927 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); 3928 } 3929 3930 START_TEST(process) 3931 { 3932 HANDLE job; 3933 BOOL b = init(); 3934 ok(b, "Basic init of CreateProcess test\n"); 3935 if (!b) return; 3936 3937 if (myARGC >= 3) 3938 { 3939 if (!strcmp(myARGV[2], "dump") && myARGC >= 4) 3940 { 3941 doChild(myARGV[3], (myARGC >= 5) ? myARGV[4] : NULL); 3942 return; 3943 } 3944 else if (!strcmp(myARGV[2], "wait")) 3945 { 3946 Sleep(30000); 3947 ok(0, "Child process not killed\n"); 3948 return; 3949 } 3950 else if (!strcmp(myARGV[2], "exit")) 3951 { 3952 Sleep(100); 3953 return; 3954 } 3955 else if (!strcmp(myARGV[2], "nested") && myARGC >= 4) 3956 { 3957 char buffer[MAX_PATH]; 3958 STARTUPINFOA startup; 3959 PROCESS_INFORMATION info; 3960 3961 memset(&startup, 0, sizeof(startup)); 3962 startup.cb = sizeof(startup); 3963 startup.dwFlags = STARTF_USESHOWWINDOW; 3964 startup.wShowWindow = SW_SHOWNORMAL; 3965 3966 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, myARGV[3]); 3967 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n"); 3968 CloseHandle(info.hProcess); 3969 CloseHandle(info.hThread); 3970 return; 3971 } 3972 3973 ok(0, "Unexpected command %s\n", myARGV[2]); 3974 return; 3975 } 3976 3977 test_process_info(); 3978 test_TerminateProcess(); 3979 test_Startup(); 3980 test_CommandLine(); 3981 test_Directory(); 3982 test_Toolhelp(); // 3983 test_Environment(); 3984 test_SuspendFlag(); 3985 test_DebuggingFlag(); 3986 test_Console(); 3987 test_ExitCode(); 3988 test_OpenProcess(); 3989 test_GetProcessVersion(); 3990 test_GetProcessImageFileNameA(); 3991 test_QueryFullProcessImageNameA(); 3992 test_QueryFullProcessImageNameW(); 3993 test_Handles(); 3994 test_IsWow64Process(); 3995 test_SystemInfo(); 3996 test_RegistryQuota(); 3997 test_DuplicateHandle(); 3998 test_StartupNoConsole(); 3999 test_DetachConsoleHandles(); 4000 test_DetachStdHandles(); 4001 test_GetNumaProcessorNode(); 4002 test_session_info(); 4003 test_GetLogicalProcessorInformationEx(); 4004 test_GetActiveProcessorCount(); 4005 test_largepages(); 4006 test_ProcThreadAttributeList(); 4007 test_SuspendProcessState(); 4008 test_SuspendProcessNewThread(); 4009 4010 /* things that can be tested: 4011 * lookup: check the way program to be executed is searched 4012 * handles: check the handle inheritance stuff (+sec options) 4013 * console: check if console creation parameters work 4014 */ 4015 4016 if (!pCreateJobObjectW) 4017 { 4018 win_skip("No job object support\n"); 4019 return; 4020 } 4021 4022 test_IsProcessInJob(); 4023 test_TerminateJobObject(); 4024 test_QueryInformationJobObject(); 4025 test_CompletionPort(); 4026 test_KillOnJobClose(); 4027 test_WaitForJobObject(); 4028 job = test_AddSelfToJob(); 4029 test_jobInheritance(job); 4030 test_BreakawayOk(job); 4031 CloseHandle(job); 4032 } 4033