ntdll: Inherit ConsoleHandle only by CUI processes.
[wine.git] / dlls / kernel32 / tests / process.c
blobf071268f0f02e825f72d470a3a7eb54a8e94a287
1 /*
2 * Unit test suite for process functions
4 * Copyright 2002 Eric Pouech
5 * Copyright 2006 Dmitry Timoshkov
6 * Copyright 2014 Michael Müller
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.
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.
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
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
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"
38 #include "wine/test.h"
39 #include "wine/heap.h"
41 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
42 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
43 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
44 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
46 #define expect_eq_d(expected, actual) \
47 do { \
48 int value = (actual); \
49 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
50 (int)(expected), value); \
51 } while (0)
52 #define expect_eq_s(expected, actual) \
53 do { \
54 LPCSTR value = (actual); \
55 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
56 expected, value); \
57 } while (0)
58 #define expect_eq_ws_i(expected, actual) \
59 do { \
60 LPCWSTR value = (actual); \
61 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
62 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
63 } while (0)
65 static HINSTANCE hkernel32, hntdll;
66 static void (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO);
67 static BOOL (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD);
68 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
69 static BOOL (WINAPI *pIsWow64Process2)(HANDLE, USHORT *, USHORT *);
70 static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize);
71 static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize);
72 static DWORD (WINAPI *pK32GetProcessImageFileNameA)(HANDLE,LPSTR,DWORD);
73 static HANDLE (WINAPI *pCreateJobObjectW)(LPSECURITY_ATTRIBUTES sa, LPCWSTR name);
74 static HANDLE (WINAPI *pOpenJobObjectA)(DWORD access, BOOL inherit, LPCSTR name);
75 static BOOL (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process);
76 static BOOL (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result);
77 static BOOL (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code);
78 static BOOL (WINAPI *pQueryInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len, LPDWORD ret_len);
79 static BOOL (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len);
80 static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads);
81 static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR);
82 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
83 static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG);
84 static NTSTATUS (WINAPI *pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS, void*, ULONG, void*, ULONG, ULONG*);
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 *pGetSystemCpuSetInformation)(SYSTEM_CPU_SET_INFORMATION*,ULONG,ULONG*,HANDLE,ULONG);
94 static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
95 static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
96 static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
97 static DWORD (WINAPI *pGetActiveProcessorCount)(WORD);
98 static DWORD (WINAPI *pGetMaximumProcessorCount)(WORD);
100 /* ############################### */
101 static char base[MAX_PATH];
102 static char selfname[MAX_PATH];
103 static char* exename;
104 static char resfile[MAX_PATH];
106 static int myARGC;
107 static char** myARGV;
109 /* As some environment variables get very long on Unix, we only test for
110 * the first 127 bytes.
111 * Note that increasing this value past 256 may exceed the buffer size
112 * limitations of the *Profile functions (at least on Wine).
114 #define MAX_LISTED_ENV_VAR 128
116 /* ---------------- portable memory allocation thingie */
118 static char memory[1024*256];
119 static char* memory_index = memory;
121 static char* grab_memory(size_t len)
123 char* ret = memory_index;
124 /* align on dword */
125 len = (len + 3) & ~3;
126 memory_index += len;
127 assert(memory_index <= memory + sizeof(memory));
128 return ret;
131 static void release_memory(void)
133 memory_index = memory;
136 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
138 static const char* encodeA(const char* str)
140 char* ptr;
141 size_t len,i;
143 if (!str) return "";
144 len = strlen(str) + 1;
145 ptr = grab_memory(len * 2 + 1);
146 for (i = 0; i < len; i++)
147 sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
148 ptr[2 * len] = '\0';
149 return ptr;
152 static const char* encodeW(const WCHAR* str)
154 char* ptr;
155 size_t len,i;
157 if (!str) return "";
158 len = lstrlenW(str) + 1;
159 ptr = grab_memory(len * 4 + 1);
160 assert(ptr);
161 for (i = 0; i < len; i++)
162 sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
163 ptr[4 * len] = '\0';
164 return ptr;
167 static unsigned decode_char(char c)
169 if (c >= '0' && c <= '9') return c - '0';
170 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
171 assert(c >= 'A' && c <= 'F');
172 return c - 'A' + 10;
175 static char* decodeA(const char* str)
177 char* ptr;
178 size_t len,i;
180 len = strlen(str) / 2;
181 if (!len--) return NULL;
182 ptr = grab_memory(len + 1);
183 for (i = 0; i < len; i++)
184 ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
185 ptr[len] = '\0';
186 return ptr;
189 /* This will be needed to decode Unicode strings saved by the child process
190 * when we test Unicode functions.
192 static WCHAR* decodeW(const char* str)
194 size_t len;
195 WCHAR* ptr;
196 int i;
198 len = strlen(str) / 4;
199 if (!len--) return NULL;
200 ptr = (WCHAR*)grab_memory(len * 2 + 1);
201 for (i = 0; i < len; i++)
202 ptr[i] = (decode_char(str[4 * i]) << 12) |
203 (decode_char(str[4 * i + 1]) << 8) |
204 (decode_char(str[4 * i + 2]) << 4) |
205 (decode_char(str[4 * i + 3]) << 0);
206 ptr[len] = '\0';
207 return ptr;
210 static void wait_and_close_child_process(PROCESS_INFORMATION *pi)
212 wait_child_process(pi->hProcess);
213 CloseHandle(pi->hThread);
214 CloseHandle(pi->hProcess);
217 static void reload_child_info(const char* resfile)
219 /* This forces the profile functions to reload the resource file
220 * after the child process has modified it.
222 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
225 /******************************************************************
226 * init
228 * generates basic information like:
229 * base: absolute path to curr dir
230 * selfname: the way to reinvoke ourselves
231 * exename: executable without the path
232 * function-pointers, which are not implemented in all windows versions
234 static BOOL init(void)
236 char *p;
238 myARGC = winetest_get_mainargs( &myARGV );
239 if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
240 strcpy(selfname, myARGV[0]);
242 /* Strip the path of selfname */
243 if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1;
244 else exename = selfname;
246 if ((p = strrchr(exename, '/')) != NULL) exename = p + 1;
248 hkernel32 = GetModuleHandleA("kernel32");
249 hntdll = GetModuleHandleA("ntdll.dll");
251 pNtQueryInformationProcess = (void *)GetProcAddress(hntdll, "NtQueryInformationProcess");
252 pNtQueryInformationThread = (void *)GetProcAddress(hntdll, "NtQueryInformationThread");
253 pNtQuerySystemInformationEx = (void *)GetProcAddress(hntdll, "NtQuerySystemInformationEx");
255 pGetNativeSystemInfo = (void *) GetProcAddress(hkernel32, "GetNativeSystemInfo");
256 pGetSystemRegistryQuota = (void *) GetProcAddress(hkernel32, "GetSystemRegistryQuota");
257 pIsWow64Process = (void *) GetProcAddress(hkernel32, "IsWow64Process");
258 pIsWow64Process2 = (void *) GetProcAddress(hkernel32, "IsWow64Process2");
259 pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA");
260 pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW");
261 pK32GetProcessImageFileNameA = (void *) GetProcAddress(hkernel32, "K32GetProcessImageFileNameA");
262 pCreateJobObjectW = (void *)GetProcAddress(hkernel32, "CreateJobObjectW");
263 pOpenJobObjectA = (void *)GetProcAddress(hkernel32, "OpenJobObjectA");
264 pAssignProcessToJobObject = (void *)GetProcAddress(hkernel32, "AssignProcessToJobObject");
265 pIsProcessInJob = (void *)GetProcAddress(hkernel32, "IsProcessInJob");
266 pTerminateJobObject = (void *)GetProcAddress(hkernel32, "TerminateJobObject");
267 pQueryInformationJobObject = (void *)GetProcAddress(hkernel32, "QueryInformationJobObject");
268 pSetInformationJobObject = (void *)GetProcAddress(hkernel32, "SetInformationJobObject");
269 pCreateIoCompletionPort = (void *)GetProcAddress(hkernel32, "CreateIoCompletionPort");
270 pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode");
271 pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId");
272 pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
273 pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First");
274 pProcess32Next = (void *)GetProcAddress(hkernel32, "Process32Next");
275 pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First");
276 pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next");
277 pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
278 pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum");
279 pGetSystemCpuSetInformation = (void *)GetProcAddress(hkernel32, "GetSystemCpuSetInformation");
280 pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
281 pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
282 pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
283 pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount");
284 pGetMaximumProcessorCount = (void *)GetProcAddress(hkernel32, "GetMaximumProcessorCount");
286 return TRUE;
289 /******************************************************************
290 * get_file_name
292 * generates an absolute file_name for temporary file
295 static void get_file_name(char* buf)
297 char path[MAX_PATH];
299 buf[0] = '\0';
300 GetTempPathA(sizeof(path), path);
301 GetTempFileNameA(path, "wt", 0, buf);
304 /******************************************************************
305 * static void childPrintf
308 static void WINAPIV __WINE_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...)
310 va_list valist;
311 char buffer[1024+4*MAX_LISTED_ENV_VAR];
312 DWORD w;
314 va_start(valist, fmt);
315 vsprintf(buffer, fmt, valist);
316 va_end(valist);
317 WriteFile(h, buffer, strlen(buffer), &w, NULL);
321 /******************************************************************
322 * doChild
324 * output most of the information in the child process
326 static void doChild(const char* file, const char* option)
328 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
329 STARTUPINFOA siA;
330 STARTUPINFOW siW;
331 int i;
332 char *ptrA, *ptrA_save;
333 WCHAR *ptrW, *ptrW_save;
334 char bufA[MAX_PATH];
335 WCHAR bufW[MAX_PATH];
336 HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
337 HANDLE snapshot;
338 PROCESSENTRY32 pe;
339 BOOL ret;
341 if (hFile == INVALID_HANDLE_VALUE) return;
343 /* output of startup info (Ansi) */
344 GetStartupInfoA(&siA);
345 childPrintf(hFile,
346 "[StartupInfoA]\ncb=%08lu\nlpDesktop=%s\nlpTitle=%s\n"
347 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
348 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
349 "dwFlags=%lu\nwShowWindow=%u\n"
350 "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n",
351 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
352 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize,
353 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute,
354 siA.dwFlags, siA.wShowWindow,
355 (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError);
357 /* check the console handles in the TEB */
358 childPrintf(hFile, "[TEB]\nhStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n",
359 (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput,
360 (DWORD_PTR)params->hStdError);
362 /* since GetStartupInfoW is only implemented in win2k,
363 * zero out before calling so we can notice the difference
365 memset(&siW, 0, sizeof(siW));
366 GetStartupInfoW(&siW);
367 childPrintf(hFile,
368 "[StartupInfoW]\ncb=%08lu\nlpDesktop=%s\nlpTitle=%s\n"
369 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
370 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
371 "dwFlags=%lu\nwShowWindow=%u\n"
372 "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n",
373 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
374 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize,
375 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute,
376 siW.dwFlags, siW.wShowWindow,
377 (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError);
379 /* Arguments */
380 childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
381 for (i = 0; i < myARGC; i++)
383 childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
385 childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
386 childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
388 /* output toolhelp information */
389 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
390 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %lu\n", GetLastError());
391 memset(&pe, 0, sizeof(pe));
392 pe.dwSize = sizeof(pe);
393 if (pProcess32First(snapshot, &pe))
395 while (pe.th32ProcessID != GetCurrentProcessId())
396 if (!pProcess32Next(snapshot, &pe)) break;
398 CloseHandle(snapshot);
399 ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n");
400 childPrintf(hFile,
401 "[Toolhelp]\ncntUsage=%lu\nth32DefaultHeapID=%Iu\n"
402 "th32ModuleID=%lu\ncntThreads=%lu\nth32ParentProcessID=%lu\n"
403 "pcPriClassBase=%lu\ndwFlags=%lu\nszExeFile=%s\n\n",
404 pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID,
405 pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase,
406 pe.dwFlags, encodeA(pe.szExeFile));
408 /* output of environment (Ansi) */
409 ptrA_save = ptrA = GetEnvironmentStringsA();
410 if (ptrA)
412 char env_var[MAX_LISTED_ENV_VAR];
414 childPrintf(hFile, "[EnvironmentA]\n");
415 i = 0;
416 while (*ptrA)
418 lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR);
419 childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
420 i++;
421 ptrA += strlen(ptrA) + 1;
423 childPrintf(hFile, "len=%d\n\n", i);
424 FreeEnvironmentStringsA(ptrA_save);
427 /* output of environment (Unicode) */
428 ptrW_save = ptrW = GetEnvironmentStringsW();
429 if (ptrW)
431 WCHAR env_var[MAX_LISTED_ENV_VAR];
433 childPrintf(hFile, "[EnvironmentW]\n");
434 i = 0;
435 while (*ptrW)
437 lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1);
438 env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
439 childPrintf(hFile, "env%d=%s\n", i, encodeW(env_var));
440 i++;
441 ptrW += lstrlenW(ptrW) + 1;
443 childPrintf(hFile, "len=%d\n\n", i);
444 FreeEnvironmentStringsW(ptrW_save);
447 childPrintf(hFile, "[Misc]\n");
448 if (GetCurrentDirectoryA(sizeof(bufA), bufA))
449 childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
450 if (GetCurrentDirectoryW(ARRAY_SIZE(bufW), bufW))
451 childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
452 childPrintf(hFile, "\n");
454 if (option && strcmp(option, "console") == 0)
456 CONSOLE_SCREEN_BUFFER_INFO sbi;
457 HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE);
458 HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
459 DWORD modeIn, modeOut;
461 childPrintf(hFile, "[Console]\n");
462 if (GetConsoleScreenBufferInfo(hConOut, &sbi))
464 childPrintf(hFile, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
465 sbi.dwSize.X, sbi.dwSize.Y, sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y, sbi.wAttributes);
466 childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
467 sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom);
468 childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n",
469 sbi.dwMaximumWindowSize.X, sbi.dwMaximumWindowSize.Y);
471 childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
472 GetConsoleCP(), GetConsoleOutputCP());
473 if (GetConsoleMode(hConIn, &modeIn))
474 childPrintf(hFile, "InputMode=%lu\n", modeIn);
475 if (GetConsoleMode(hConOut, &modeOut))
476 childPrintf(hFile, "OutputMode=%lu\n", modeOut);
478 /* now that we have written all relevant information, let's change it */
479 SetLastError(0xdeadbeef);
480 ret = SetConsoleCP(1252);
481 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
483 win_skip("Setting the codepage is not implemented\n");
485 else
487 ok(ret, "Setting CP\n");
488 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
491 ret = SetConsoleMode(hConIn, modeIn ^ 1);
492 ok( ret, "Setting mode (%ld)\n", GetLastError());
493 ret = SetConsoleMode(hConOut, modeOut ^ 1);
494 ok( ret, "Setting mode (%ld)\n", GetLastError());
495 sbi.dwCursorPosition.X ^= 1;
496 sbi.dwCursorPosition.Y ^= 1;
497 ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition);
498 ok( ret, "Setting cursor position (%ld)\n", GetLastError());
500 if (option && strcmp(option, "stdhandle") == 0)
502 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
503 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
505 if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE)
507 char buf[1024];
508 DWORD r, w;
510 ok(ReadFile(hStdIn, buf, sizeof(buf), &r, NULL) && r > 0, "Reading message from input pipe\n");
511 childPrintf(hFile, "[StdHandle]\nmsg=%s\n\n", encodeA(buf));
512 ok(WriteFile(hStdOut, buf, r, &w, NULL) && w == r, "Writing message to output pipe\n");
516 if (option && strcmp(option, "exit_code") == 0)
518 childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123);
519 CloseHandle(hFile);
520 ExitProcess(123);
523 CloseHandle(hFile);
526 static char* getChildString(const char* sect, const char* key)
528 char buf[1024+4*MAX_LISTED_ENV_VAR];
529 char* ret;
531 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
532 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
533 assert(!(strlen(buf) & 1));
534 ret = decodeA(buf);
535 return ret;
538 static WCHAR* getChildStringW(const char* sect, const char* key)
540 char buf[1024+4*MAX_LISTED_ENV_VAR];
541 WCHAR* ret;
543 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
544 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
545 assert(!(strlen(buf) & 1));
546 ret = decodeW(buf);
547 return ret;
550 static int strCmp(const char* s1, const char* s2, BOOL sensitive)
552 if (!s1 && !s2) return 0;
553 if (!s2) return -1;
554 if (!s1) return 1;
555 return (sensitive) ? strcmp(s1, s2) : strcasecmp(s1, s2);
558 static void ok_child_string( int line, const char *sect, const char *key,
559 const char *expect, int sensitive )
561 char* result = getChildString( sect, key );
562 ok_(__FILE__, line)( strCmp(result, expect, sensitive) == 0, "%s:%s expected '%s', got '%s'\n",
563 sect, key, expect ? expect : "(null)", result );
566 static void ok_child_stringWA( int line, const char *sect, const char *key,
567 const char *expect, int sensitive )
569 WCHAR* expectW;
570 CHAR* resultA;
571 DWORD len;
572 WCHAR* result = getChildStringW( sect, key );
574 len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0);
575 expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
576 MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len);
578 len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL);
579 resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR));
580 WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL);
582 if (sensitive)
583 ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
584 sect, key, expect ? expect : "(null)", resultA );
585 else
586 ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
587 sect, key, expect ? expect : "(null)", resultA );
588 HeapFree(GetProcessHeap(),0,expectW);
589 HeapFree(GetProcessHeap(),0,resultA);
592 static void ok_child_int( int line, const char *sect, const char *key, UINT expect )
594 UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile );
595 ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result );
598 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
599 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
600 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
601 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
603 static void test_Startup(void)
605 char buffer[2 * MAX_PATH + 25];
606 PROCESS_INFORMATION info;
607 STARTUPINFOA startup,si;
608 char *result;
609 static CHAR title[] = "I'm the title string",
610 desktop[] = "winsta0\\default",
611 empty[] = "";
613 /* let's start simplistic */
614 memset(&startup, 0, sizeof(startup));
615 startup.cb = sizeof(startup);
616 startup.dwFlags = STARTF_USESHOWWINDOW;
617 startup.wShowWindow = SW_SHOWNORMAL;
619 get_file_name(resfile);
620 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
621 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
622 wait_and_close_child_process(&info);
624 reload_child_info(resfile);
625 GetStartupInfoA(&si);
626 okChildInt("StartupInfoA", "cb", startup.cb);
627 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
628 okChildInt("StartupInfoA", "dwX", startup.dwX);
629 okChildInt("StartupInfoA", "dwY", startup.dwY);
630 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
631 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
632 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
633 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
634 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
635 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
636 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
637 release_memory();
638 DeleteFileA(resfile);
640 /* not so simplistic now */
641 memset(&startup, 0, sizeof(startup));
642 startup.cb = sizeof(startup);
643 startup.dwFlags = STARTF_USESHOWWINDOW;
644 startup.wShowWindow = SW_SHOWNORMAL;
645 startup.lpTitle = title;
646 startup.lpDesktop = desktop;
647 startup.dwXCountChars = 0x12121212;
648 startup.dwYCountChars = 0x23232323;
649 startup.dwX = 0x34343434;
650 startup.dwY = 0x45454545;
651 startup.dwXSize = 0x56565656;
652 startup.dwYSize = 0x67676767;
653 startup.dwFillAttribute = 0xA55A;
655 get_file_name(resfile);
656 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
657 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
658 wait_and_close_child_process(&info);
660 reload_child_info(resfile);
661 okChildInt("StartupInfoA", "cb", startup.cb);
662 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
663 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
664 okChildInt("StartupInfoA", "dwX", startup.dwX);
665 okChildInt("StartupInfoA", "dwY", startup.dwY);
666 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
667 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
668 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
669 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
670 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
671 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
672 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
673 release_memory();
674 DeleteFileA(resfile);
676 /* not so simplistic now */
677 memset(&startup, 0, sizeof(startup));
678 startup.cb = sizeof(startup);
679 startup.dwFlags = STARTF_USESHOWWINDOW;
680 startup.wShowWindow = SW_SHOWNORMAL;
681 startup.lpTitle = title;
682 startup.lpDesktop = NULL;
683 startup.dwXCountChars = 0x12121212;
684 startup.dwYCountChars = 0x23232323;
685 startup.dwX = 0x34343434;
686 startup.dwY = 0x45454545;
687 startup.dwXSize = 0x56565656;
688 startup.dwYSize = 0x67676767;
689 startup.dwFillAttribute = 0xA55A;
691 get_file_name(resfile);
692 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
693 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
694 wait_and_close_child_process(&info);
696 reload_child_info(resfile);
697 okChildInt("StartupInfoA", "cb", startup.cb);
698 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
699 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
700 okChildInt("StartupInfoA", "dwX", startup.dwX);
701 okChildInt("StartupInfoA", "dwY", startup.dwY);
702 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
703 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
704 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
705 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
706 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
707 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
708 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
709 release_memory();
710 DeleteFileA(resfile);
712 /* not so simplistic now */
713 memset(&startup, 0, sizeof(startup));
714 startup.cb = sizeof(startup);
715 startup.dwFlags = STARTF_USESHOWWINDOW;
716 startup.wShowWindow = SW_SHOWNORMAL;
717 startup.lpTitle = title;
718 startup.lpDesktop = empty;
719 startup.dwXCountChars = 0x12121212;
720 startup.dwYCountChars = 0x23232323;
721 startup.dwX = 0x34343434;
722 startup.dwY = 0x45454545;
723 startup.dwXSize = 0x56565656;
724 startup.dwYSize = 0x67676767;
725 startup.dwFillAttribute = 0xA55A;
727 get_file_name(resfile);
728 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
729 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
730 wait_and_close_child_process(&info);
732 reload_child_info(resfile);
733 okChildInt("StartupInfoA", "cb", startup.cb);
734 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
735 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
736 okChildInt("StartupInfoA", "dwX", startup.dwX);
737 okChildInt("StartupInfoA", "dwY", startup.dwY);
738 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
739 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
740 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
741 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
742 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
743 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
744 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
745 release_memory();
746 DeleteFileA(resfile);
748 /* not so simplistic now */
749 memset(&startup, 0, sizeof(startup));
750 startup.cb = sizeof(startup);
751 startup.dwFlags = STARTF_USESHOWWINDOW;
752 startup.wShowWindow = SW_SHOWNORMAL;
753 startup.lpTitle = NULL;
754 startup.lpDesktop = desktop;
755 startup.dwXCountChars = 0x12121212;
756 startup.dwYCountChars = 0x23232323;
757 startup.dwX = 0x34343434;
758 startup.dwY = 0x45454545;
759 startup.dwXSize = 0x56565656;
760 startup.dwYSize = 0x67676767;
761 startup.dwFillAttribute = 0xA55A;
763 get_file_name(resfile);
764 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
765 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
766 wait_and_close_child_process(&info);
768 reload_child_info(resfile);
769 okChildInt("StartupInfoA", "cb", startup.cb);
770 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
771 result = getChildString( "StartupInfoA", "lpTitle" );
772 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
773 "expected '%s' or null, got '%s'\n", selfname, result );
774 okChildInt("StartupInfoA", "dwX", startup.dwX);
775 okChildInt("StartupInfoA", "dwY", startup.dwY);
776 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
777 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
778 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
779 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
780 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
781 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
782 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
783 release_memory();
784 DeleteFileA(resfile);
786 /* not so simplistic now */
787 memset(&startup, 0, sizeof(startup));
788 startup.cb = sizeof(startup);
789 startup.dwFlags = STARTF_USESHOWWINDOW;
790 startup.wShowWindow = SW_SHOWNORMAL;
791 startup.lpTitle = empty;
792 startup.lpDesktop = desktop;
793 startup.dwXCountChars = 0x12121212;
794 startup.dwYCountChars = 0x23232323;
795 startup.dwX = 0x34343434;
796 startup.dwY = 0x45454545;
797 startup.dwXSize = 0x56565656;
798 startup.dwYSize = 0x67676767;
799 startup.dwFillAttribute = 0xA55A;
801 get_file_name(resfile);
802 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
803 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
804 wait_and_close_child_process(&info);
806 reload_child_info(resfile);
807 okChildInt("StartupInfoA", "cb", startup.cb);
808 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
809 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
810 okChildInt("StartupInfoA", "dwX", startup.dwX);
811 okChildInt("StartupInfoA", "dwY", startup.dwY);
812 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
813 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
814 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
815 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
816 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
817 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
818 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
819 release_memory();
820 DeleteFileA(resfile);
822 /* not so simplistic now */
823 memset(&startup, 0, sizeof(startup));
824 startup.cb = sizeof(startup);
825 startup.dwFlags = STARTF_USESHOWWINDOW;
826 startup.wShowWindow = SW_SHOWNORMAL;
827 startup.lpTitle = empty;
828 startup.lpDesktop = empty;
829 startup.dwXCountChars = 0x12121212;
830 startup.dwYCountChars = 0x23232323;
831 startup.dwX = 0x34343434;
832 startup.dwY = 0x45454545;
833 startup.dwXSize = 0x56565656;
834 startup.dwYSize = 0x67676767;
835 startup.dwFillAttribute = 0xA55A;
837 get_file_name(resfile);
838 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
839 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
840 wait_and_close_child_process(&info);
842 reload_child_info(resfile);
843 okChildInt("StartupInfoA", "cb", startup.cb);
844 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
845 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
846 okChildInt("StartupInfoA", "dwX", startup.dwX);
847 okChildInt("StartupInfoA", "dwY", startup.dwY);
848 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
849 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
850 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
851 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
852 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
853 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
854 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
855 release_memory();
856 DeleteFileA(resfile);
858 /* TODO: test for A/W and W/A and W/W */
861 static void test_CommandLine(void)
863 char buffer[2 * MAX_PATH + 65], fullpath[MAX_PATH], *lpFilePart, *p;
864 char buffer2[MAX_PATH + 44];
865 PROCESS_INFORMATION info;
866 STARTUPINFOA startup;
867 BOOL ret;
868 LPWSTR cmdline, cmdline_backup;
870 memset(&startup, 0, sizeof(startup));
871 startup.cb = sizeof(startup);
872 startup.dwFlags = STARTF_USESHOWWINDOW;
873 startup.wShowWindow = SW_SHOWNORMAL;
875 /* failure case */
876 strcpy(buffer, "\"t:\\NotADir\\NotAFile.exe\"");
877 memset(&info, 0xa, sizeof(info));
878 ok(!CreateProcessA(buffer, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess unexpectedly succeeded\n");
879 /* Check that the effective STARTUPINFOA parameters are not modified */
880 ok(startup.cb == sizeof(startup), "unexpected cb %ld\n", startup.cb);
881 ok(startup.lpDesktop == NULL, "lpDesktop is not NULL\n");
882 ok(startup.lpTitle == NULL, "lpTitle is not NULL\n");
883 ok(startup.dwFlags == STARTF_USESHOWWINDOW, "unexpected dwFlags %04lx\n", startup.dwFlags);
884 ok(startup.wShowWindow == SW_SHOWNORMAL, "unexpected wShowWindow %d\n", startup.wShowWindow);
885 ok(!info.hProcess, "unexpected hProcess %p\n", info.hProcess);
886 ok(!info.hThread, "unexpected hThread %p\n", info.hThread);
887 ok(!info.dwProcessId, "unexpected dwProcessId %04lx\n", info.dwProcessId);
888 ok(!info.dwThreadId, "unexpected dwThreadId %04lx\n", info.dwThreadId);
890 /* the basics; not getting confused by the leading and trailing " */
891 get_file_name(resfile);
892 sprintf(buffer, "\"%s\" process dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
893 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
894 /* Check that the effective STARTUPINFOA parameters are not modified */
895 ok(startup.cb == sizeof(startup), "unexpected cb %ld\n", startup.cb);
896 ok(startup.lpDesktop == NULL, "lpDesktop is not NULL\n");
897 ok(startup.lpTitle == NULL, "lpTitle is not NULL\n");
898 ok(startup.dwFlags == STARTF_USESHOWWINDOW, "unexpected dwFlags %04lx\n", startup.dwFlags);
899 ok(startup.wShowWindow == SW_SHOWNORMAL, "unexpected wShowWindow %d\n", startup.wShowWindow);
900 wait_and_close_child_process(&info);
902 reload_child_info(resfile);
903 okChildInt("Arguments", "argcA", 5);
904 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
905 okChildString("Arguments", "argvA5", NULL);
906 okChildString("Arguments", "CommandLineA", buffer);
907 release_memory();
908 DeleteFileA(resfile);
910 /* test main()'s quotes handling */
911 get_file_name(resfile);
912 sprintf(buffer, "\"%s\" process dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
913 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
914 wait_and_close_child_process(&info);
916 reload_child_info(resfile);
917 okChildInt("Arguments", "argcA", 7);
918 okChildString("Arguments", "argvA4", "a\"b\\");
919 okChildString("Arguments", "argvA5", "c\"");
920 okChildString("Arguments", "argvA6", "d");
921 okChildString("Arguments", "argvA7", NULL);
922 okChildString("Arguments", "CommandLineA", buffer);
923 release_memory();
924 DeleteFileA(resfile);
926 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
927 assert ( lpFilePart != 0);
928 *(lpFilePart -1 ) = 0;
929 SetCurrentDirectoryA( fullpath );
931 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]
932 * and " escaping.
934 get_file_name(resfile);
935 /* Use exename to avoid buffer containing things like 'C:' */
936 sprintf(buffer, "./%s process dump \"%s\" \"\"\"\"", exename, resfile);
937 SetLastError(0xdeadbeef);
938 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
939 ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError());
940 wait_and_close_child_process(&info);
942 reload_child_info(resfile);
943 sprintf(buffer, "./%s", exename);
944 okChildInt("Arguments", "argcA", 5);
945 okChildString("Arguments", "argvA0", buffer);
946 okChildString("Arguments", "argvA4", "\"");
947 okChildString("Arguments", "argvA5", NULL);
948 release_memory();
949 DeleteFileA(resfile);
951 get_file_name(resfile);
952 /* Use exename to avoid buffer containing things like 'C:' */
953 sprintf(buffer, ".\\%s process dump \"%s\"", exename, resfile);
954 SetLastError(0xdeadbeef);
955 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
956 ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError());
957 wait_and_close_child_process(&info);
959 reload_child_info(resfile);
960 sprintf(buffer, ".\\%s", exename);
961 okChildString("Arguments", "argvA0", buffer);
962 release_memory();
963 DeleteFileA(resfile);
965 get_file_name(resfile);
966 p = strrchr(fullpath, '\\');
967 /* Use exename to avoid buffer containing things like 'C:' */
968 if (p) sprintf(buffer, "..%s/%s process dump \"%s\"", p, exename, resfile);
969 else sprintf(buffer, "./%s process dump \"%s\"", exename, resfile);
970 SetLastError(0xdeadbeef);
971 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
972 ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError());
973 wait_and_close_child_process(&info);
975 reload_child_info(resfile);
976 if (p) sprintf(buffer, "..%s/%s", p, exename);
977 else sprintf(buffer, "./%s", exename);
978 okChildString("Arguments", "argvA0", buffer);
979 release_memory();
980 DeleteFileA(resfile);
982 /* Using AppName */
983 get_file_name(resfile);
984 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
985 assert ( lpFilePart != 0);
986 *(lpFilePart -1 ) = 0;
987 p = strrchr(fullpath, '\\');
988 /* Use exename to avoid buffer containing things like 'C:' */
989 if (p) sprintf(buffer, "..%s/%s", p, exename);
990 else sprintf(buffer, "./%s", exename);
991 sprintf(buffer2, "dummy process dump \"%s\"", resfile);
992 SetLastError(0xdeadbeef);
993 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
994 ok(ret, "CreateProcess (%s) failed : %ld\n", buffer, GetLastError());
995 wait_and_close_child_process(&info);
997 reload_child_info(resfile);
998 okChildString("Arguments", "argvA0", "dummy");
999 okChildString("Arguments", "CommandLineA", buffer2);
1000 okChildStringWA("Arguments", "CommandLineW", buffer2);
1001 release_memory();
1002 DeleteFileA(resfile);
1003 SetCurrentDirectoryA( base );
1005 if (0) /* Test crashes on NT-based Windows. */
1007 /* Test NULL application name and command line parameters. */
1008 SetLastError(0xdeadbeef);
1009 ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1010 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1011 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1012 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
1015 buffer[0] = '\0';
1017 /* Test empty application name parameter. */
1018 SetLastError(0xdeadbeef);
1019 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1020 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1021 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1022 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1023 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1024 "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError());
1026 buffer2[0] = '\0';
1028 /* Test empty application name and command line parameters. */
1029 SetLastError(0xdeadbeef);
1030 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1031 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1032 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1033 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1034 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1035 "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError());
1037 /* Test empty command line parameter. */
1038 SetLastError(0xdeadbeef);
1039 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1040 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1041 ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
1042 GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ ||
1043 GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ ||
1044 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */,
1045 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1047 strcpy(buffer, "doesnotexist.exe");
1048 strcpy(buffer2, "does not exist.exe");
1050 /* Test nonexistent application name. */
1051 SetLastError(0xdeadbeef);
1052 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1053 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1054 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1056 SetLastError(0xdeadbeef);
1057 ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1058 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1059 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1061 /* Test nonexistent command line parameter. */
1062 SetLastError(0xdeadbeef);
1063 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1064 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1065 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1067 SetLastError(0xdeadbeef);
1068 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1069 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1070 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1072 /* Test whether GetCommandLineW reads directly from TEB or from a cached address */
1073 cmdline = GetCommandLineW();
1074 ok(cmdline == NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer, "Expected address from TEB, got %p\n", cmdline);
1076 cmdline_backup = cmdline;
1077 NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer = NULL;
1078 cmdline = GetCommandLineW();
1079 ok(cmdline == cmdline_backup, "Expected cached address from TEB, got %p\n", cmdline);
1080 NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer = cmdline_backup;
1083 static void test_Directory(void)
1085 char buffer[2 * MAX_PATH + 25];
1086 PROCESS_INFORMATION info;
1087 STARTUPINFOA startup;
1088 char windir[MAX_PATH];
1089 static CHAR cmdline[] = "winver.exe";
1091 memset(&startup, 0, sizeof(startup));
1092 startup.cb = sizeof(startup);
1093 startup.dwFlags = STARTF_USESHOWWINDOW;
1094 startup.wShowWindow = SW_SHOWNORMAL;
1096 /* the basics */
1097 get_file_name(resfile);
1098 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1099 GetWindowsDirectoryA( windir, sizeof(windir) );
1100 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n");
1101 wait_and_close_child_process(&info);
1103 reload_child_info(resfile);
1104 okChildIString("Misc", "CurrDirA", windir);
1105 release_memory();
1106 DeleteFileA(resfile);
1108 /* search PATH for the exe if directory is NULL */
1109 ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1110 ok(TerminateProcess(info.hProcess, 0), "Child process termination\n");
1111 CloseHandle(info.hThread);
1112 CloseHandle(info.hProcess);
1114 /* if any directory is provided, don't search PATH, error on bad directory */
1115 SetLastError(0xdeadbeef);
1116 memset(&info, 0, sizeof(info));
1117 ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L,
1118 NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n");
1119 ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %ld\n", GetLastError());
1120 ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n");
1123 static void test_Toolhelp(void)
1125 char buffer[2 * MAX_PATH + 27];
1126 STARTUPINFOA startup;
1127 PROCESS_INFORMATION info;
1128 HANDLE process, thread, snapshot;
1129 DWORD nested_pid;
1130 PROCESSENTRY32 pe;
1131 THREADENTRY32 te;
1132 DWORD ret;
1133 int i;
1135 memset(&startup, 0, sizeof(startup));
1136 startup.cb = sizeof(startup);
1137 startup.dwFlags = STARTF_USESHOWWINDOW;
1138 startup.wShowWindow = SW_SHOWNORMAL;
1140 get_file_name(resfile);
1141 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1142 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1143 wait_and_close_child_process(&info);
1145 reload_child_info(resfile);
1146 okChildInt("Toolhelp", "cntUsage", 0);
1147 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1148 okChildInt("Toolhelp", "th32ModuleID", 0);
1149 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1150 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1151 okChildInt("Toolhelp", "dwFlags", 0);
1153 release_memory();
1154 DeleteFileA(resfile);
1156 get_file_name(resfile);
1157 sprintf(buffer, "\"%s\" process nested \"%s\"", selfname, resfile);
1158 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1159 wait_child_process(info.hProcess);
1161 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1162 ok(process != NULL, "OpenProcess failed %lu\n", GetLastError());
1163 CloseHandle(process);
1165 CloseHandle(info.hProcess);
1166 CloseHandle(info.hThread);
1168 for (i = 0; i < 20; i++)
1170 SetLastError(0xdeadbeef);
1171 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1172 ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %lu\n", GetLastError());
1173 if (!process) break;
1174 CloseHandle(process);
1175 Sleep(100);
1177 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1178 ok(i < 20 || broken(i == 20), "process object not released\n");
1180 /* Look for the nested process by pid */
1181 reload_child_info(resfile);
1182 nested_pid = GetPrivateProfileIntA("Nested", "Pid", 0, resfile);
1183 DeleteFileA(resfile);
1185 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1186 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %lu\n", GetLastError());
1187 memset(&pe, 0, sizeof(pe));
1188 pe.dwSize = sizeof(pe);
1189 if (pProcess32First(snapshot, &pe))
1191 while (pe.th32ProcessID != nested_pid)
1192 if (!pProcess32Next(snapshot, &pe)) break;
1194 CloseHandle(snapshot);
1195 ok(pe.th32ProcessID == nested_pid, "failed to find nested child process\n");
1196 ok(pe.th32ParentProcessID == info.dwProcessId, "nested child process has parent %lu instead of %lu\n", pe.th32ParentProcessID, info.dwProcessId);
1197 ok(stricmp(pe.szExeFile, exename) == 0, "nested executable is %s instead of %s\n", pe.szExeFile, exename);
1199 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID);
1200 ok(process != NULL, "OpenProcess failed %lu\n", GetLastError());
1202 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1203 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %lu\n", GetLastError());
1204 memset(&te, 0, sizeof(te));
1205 te.dwSize = sizeof(te);
1206 if (pThread32First(snapshot, &te))
1208 while (te.th32OwnerProcessID != pe.th32ProcessID)
1209 if (!pThread32Next(snapshot, &te)) break;
1211 CloseHandle(snapshot);
1212 ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1214 thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID);
1215 ok(thread != NULL, "OpenThread failed %lu\n", GetLastError());
1216 ret = ResumeThread(thread);
1217 ok(ret == 1, "expected 1, got %lu\n", ret);
1218 CloseHandle(thread);
1220 wait_child_process(process);
1221 CloseHandle(process);
1223 reload_child_info(resfile);
1224 okChildInt("Toolhelp", "cntUsage", 0);
1225 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1226 okChildInt("Toolhelp", "th32ModuleID", 0);
1227 okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1228 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1229 okChildInt("Toolhelp", "dwFlags", 0);
1231 release_memory();
1232 DeleteFileA(resfile);
1235 static BOOL is_str_env_drive_dir(const char* str)
1237 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1238 str[3] == '=' && str[4] == str[1];
1241 /* compared expected child's environment (in gesA) from actual
1242 * environment our child got
1244 static void cmpEnvironment(const char* gesA)
1246 int i, clen;
1247 const char* ptrA;
1248 char* res;
1249 char key[32];
1250 BOOL found;
1252 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1254 /* now look each parent env in child */
1255 if ((ptrA = gesA) != NULL)
1257 while (*ptrA)
1259 for (i = 0; i < clen; i++)
1261 sprintf(key, "env%d", i);
1262 res = getChildString("EnvironmentA", key);
1263 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1264 break;
1266 found = i < clen;
1267 ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1269 ptrA += strlen(ptrA) + 1;
1270 release_memory();
1273 /* and each child env in parent */
1274 for (i = 0; i < clen; i++)
1276 sprintf(key, "env%d", i);
1277 res = getChildString("EnvironmentA", key);
1278 if ((ptrA = gesA) != NULL)
1280 while (*ptrA)
1282 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1283 break;
1284 ptrA += strlen(ptrA) + 1;
1286 if (!*ptrA) ptrA = NULL;
1289 if (!is_str_env_drive_dir(res))
1291 found = ptrA != NULL;
1292 ok(found, "Child-env string %s isn't in parent process\n", res);
1294 /* else => should also test we get the right per drive default directory here... */
1298 static void test_Environment(void)
1300 char buffer[2 * MAX_PATH + 25];
1301 PROCESS_INFORMATION info;
1302 STARTUPINFOA startup;
1303 char *child_env;
1304 int child_env_len;
1305 char *ptr;
1306 char *ptr2;
1307 char *env;
1308 int slen;
1310 memset(&startup, 0, sizeof(startup));
1311 startup.cb = sizeof(startup);
1312 startup.dwFlags = STARTF_USESHOWWINDOW;
1313 startup.wShowWindow = SW_SHOWNORMAL;
1315 /* the basics */
1316 get_file_name(resfile);
1317 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1318 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1319 wait_and_close_child_process(&info);
1321 reload_child_info(resfile);
1322 env = GetEnvironmentStringsA();
1323 cmpEnvironment(env);
1324 release_memory();
1325 DeleteFileA(resfile);
1327 memset(&startup, 0, sizeof(startup));
1328 startup.cb = sizeof(startup);
1329 startup.dwFlags = STARTF_USESHOWWINDOW;
1330 startup.wShowWindow = SW_SHOWNORMAL;
1332 /* the basics */
1333 get_file_name(resfile);
1334 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1336 child_env_len = 0;
1337 ptr = env;
1338 while(*ptr)
1340 slen = strlen(ptr)+1;
1341 child_env_len += slen;
1342 ptr += slen;
1344 /* Add space for additional environment variables */
1345 child_env_len += 256;
1346 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1348 ptr = child_env;
1349 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1350 ptr += strlen(ptr) + 1;
1351 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1352 ptr += strlen(ptr) + 1;
1353 strcpy(ptr, "FOO=BAR");
1354 ptr += strlen(ptr) + 1;
1355 strcpy(ptr, "BAR=FOOBAR");
1356 ptr += strlen(ptr) + 1;
1357 /* copy all existing variables except:
1358 * - PATH (already set above)
1359 * - the directory definitions (=[A-Z]:=)
1361 for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1363 if (strncmp(ptr2, "PATH=", 5) != 0 &&
1364 !is_str_env_drive_dir(ptr2))
1366 strcpy(ptr, ptr2);
1367 ptr += strlen(ptr) + 1;
1370 *ptr = '\0';
1371 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1372 wait_and_close_child_process(&info);
1374 reload_child_info(resfile);
1375 cmpEnvironment(child_env);
1377 HeapFree(GetProcessHeap(), 0, child_env);
1378 FreeEnvironmentStringsA(env);
1379 release_memory();
1380 DeleteFileA(resfile);
1383 static void test_SuspendFlag(void)
1385 char buffer[2 * MAX_PATH + 25];
1386 PROCESS_INFORMATION info;
1387 STARTUPINFOA startup, us;
1388 DWORD exit_status;
1389 char *result;
1391 /* let's start simplistic */
1392 memset(&startup, 0, sizeof(startup));
1393 startup.cb = sizeof(startup);
1394 startup.dwFlags = STARTF_USESHOWWINDOW;
1395 startup.wShowWindow = SW_SHOWNORMAL;
1397 get_file_name(resfile);
1398 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1399 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1401 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1402 Sleep(100);
1403 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1404 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1406 wait_and_close_child_process(&info);
1408 GetStartupInfoA(&us);
1410 reload_child_info(resfile);
1411 okChildInt("StartupInfoA", "cb", startup.cb);
1412 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1413 result = getChildString( "StartupInfoA", "lpTitle" );
1414 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1415 "expected '%s' or null, got '%s'\n", selfname, result );
1416 okChildInt("StartupInfoA", "dwX", startup.dwX);
1417 okChildInt("StartupInfoA", "dwY", startup.dwY);
1418 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1419 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1420 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1421 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1422 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1423 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1424 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1425 release_memory();
1426 DeleteFileA(resfile);
1429 static void test_DebuggingFlag(void)
1431 char buffer[2 * MAX_PATH + 25];
1432 void *processbase = NULL;
1433 PROCESS_INFORMATION info;
1434 STARTUPINFOA startup, us;
1435 DEBUG_EVENT de;
1436 unsigned dbg = 0;
1437 char *result;
1439 /* let's start simplistic */
1440 memset(&startup, 0, sizeof(startup));
1441 startup.cb = sizeof(startup);
1442 startup.dwFlags = STARTF_USESHOWWINDOW;
1443 startup.wShowWindow = SW_SHOWNORMAL;
1445 get_file_name(resfile);
1446 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
1447 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1449 /* get all startup events up to the entry point break exception */
1452 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1453 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1454 if (!dbg)
1456 ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1457 "first event: %ld\n", de.dwDebugEventCode);
1458 processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1460 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1461 ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT ||
1462 de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1463 } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1465 ok(dbg, "I have seen a debug event\n");
1466 wait_and_close_child_process(&info);
1468 GetStartupInfoA(&us);
1470 reload_child_info(resfile);
1471 okChildInt("StartupInfoA", "cb", startup.cb);
1472 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1473 result = getChildString( "StartupInfoA", "lpTitle" );
1474 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1475 "expected '%s' or null, got '%s'\n", selfname, result );
1476 okChildInt("StartupInfoA", "dwX", startup.dwX);
1477 okChildInt("StartupInfoA", "dwY", startup.dwY);
1478 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1479 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1480 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1481 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1482 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1483 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1484 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1485 release_memory();
1486 DeleteFileA(resfile);
1489 static void test_Console(void)
1491 char buffer[2 * MAX_PATH + 35];
1492 PROCESS_INFORMATION info;
1493 STARTUPINFOA startup, us;
1494 SECURITY_ATTRIBUTES sa;
1495 CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC;
1496 DWORD modeIn, modeOut, modeInC, modeOutC;
1497 DWORD cpIn, cpOut, cpInC, cpOutC;
1498 DWORD w;
1499 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1500 const char* msg = "This is a std-handle inheritance test.";
1501 unsigned msg_len;
1502 BOOL run_tests = TRUE;
1503 char *result;
1505 memset(&startup, 0, sizeof(startup));
1506 startup.cb = sizeof(startup);
1507 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1508 startup.wShowWindow = SW_SHOWNORMAL;
1510 sa.nLength = sizeof(sa);
1511 sa.lpSecurityDescriptor = NULL;
1512 sa.bInheritHandle = TRUE;
1514 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1515 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1517 /* first, we need to be sure we're attached to a console */
1518 if (startup.hStdInput == INVALID_HANDLE_VALUE || startup.hStdOutput == INVALID_HANDLE_VALUE)
1520 /* this fails either when this test process is run detached from console
1521 * (unlikely, as this very process must be explicitly created with detached flag),
1522 * or is attached to a Wine's shell-no-window kind of console (if the later, detach from it)
1524 FreeConsole();
1525 /* we're not attached to a console, let's do it */
1526 AllocConsole();
1527 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1528 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1530 /* now verify everything's ok */
1531 ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1532 ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1533 startup.hStdError = startup.hStdOutput;
1535 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1536 ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1537 ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1538 cpIn = GetConsoleCP();
1539 cpOut = GetConsoleOutputCP();
1541 get_file_name(resfile);
1542 sprintf(buffer, "\"%s\" process dump \"%s\" console", selfname, resfile);
1543 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1544 wait_and_close_child_process(&info);
1546 reload_child_info(resfile);
1547 /* now get the modification the child has made, and resets parents expected values */
1548 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1549 ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1550 ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1552 SetConsoleMode(startup.hStdInput, modeIn);
1553 SetConsoleMode(startup.hStdOutput, modeOut);
1555 /* don't test flag that is changed at startup if WINETEST_COLOR is set */
1556 modeOut = (modeOut & ~ENABLE_VIRTUAL_TERMINAL_PROCESSING) |
1557 (modeOutC & ENABLE_VIRTUAL_TERMINAL_PROCESSING);
1559 cpInC = GetConsoleCP();
1560 cpOutC = GetConsoleOutputCP();
1562 /* Try to set invalid CP */
1563 SetLastError(0xdeadbeef);
1564 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1565 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1566 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1567 "GetLastError: expecting %u got %lu\n",
1568 ERROR_INVALID_PARAMETER, GetLastError());
1569 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1570 run_tests = FALSE;
1573 SetLastError(0xdeadbeef);
1574 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1575 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1576 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1577 "GetLastError: expecting %u got %lu\n",
1578 ERROR_INVALID_PARAMETER, GetLastError());
1580 SetConsoleCP(cpIn);
1581 SetConsoleOutputCP(cpOut);
1583 GetStartupInfoA(&us);
1585 okChildInt("StartupInfoA", "cb", startup.cb);
1586 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1587 result = getChildString( "StartupInfoA", "lpTitle" );
1588 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1589 "expected '%s' or null, got '%s'\n", selfname, result );
1590 okChildInt("StartupInfoA", "dwX", startup.dwX);
1591 okChildInt("StartupInfoA", "dwY", startup.dwY);
1592 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1593 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1594 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1595 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1596 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1597 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1598 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1600 /* check child correctly inherited the console */
1601 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1602 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1603 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1604 okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1605 okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1606 okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1607 okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1608 okChildInt("Console", "Attributes", sbi.wAttributes);
1609 okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1610 okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1611 okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1612 okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1613 okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1614 okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1615 okChildInt("Console", "InputCP", cpIn);
1616 okChildInt("Console", "OutputCP", cpOut);
1617 okChildInt("Console", "InputMode", modeIn);
1618 okChildInt("Console", "OutputMode", modeOut);
1620 if (run_tests)
1622 ok(cpInC == 1252, "Wrong console CP (expected 1252 got %ld/%ld)\n", cpInC, cpIn);
1623 ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %ld/%ld)\n", cpOutC, cpOut);
1625 else
1626 win_skip("Setting the codepage is not implemented\n");
1628 ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1629 ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1631 release_memory();
1632 DeleteFileA(resfile);
1634 ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1635 ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(),
1636 &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1637 "Duplicating as inheritable child-output pipe\n");
1638 CloseHandle(hChildOut);
1640 ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1641 ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(),
1642 &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1643 "Duplicating as inheritable child-input pipe\n");
1644 CloseHandle(hChildIn);
1646 memset(&startup, 0, sizeof(startup));
1647 startup.cb = sizeof(startup);
1648 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1649 startup.wShowWindow = SW_SHOWNORMAL;
1650 startup.hStdInput = hChildInInh;
1651 startup.hStdOutput = hChildOutInh;
1652 startup.hStdError = hChildOutInh;
1654 get_file_name(resfile);
1655 sprintf(buffer, "\"%s\" process dump \"%s\" stdhandle", selfname, resfile);
1656 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1657 ok(CloseHandle(hChildInInh), "Closing handle\n");
1658 ok(CloseHandle(hChildOutInh), "Closing handle\n");
1660 msg_len = strlen(msg) + 1;
1661 ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1662 ok(w == msg_len, "Should have written %u bytes, actually wrote %lu\n", msg_len, w);
1663 memset(buffer, 0, sizeof(buffer));
1664 ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1665 ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1667 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1668 ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1670 wait_and_close_child_process(&info);
1672 reload_child_info(resfile);
1673 okChildString("StdHandle", "msg", msg);
1675 release_memory();
1676 DeleteFileA(resfile);
1679 static void test_ExitCode(void)
1681 char buffer[2 * MAX_PATH + 35];
1682 PROCESS_INFORMATION info;
1683 STARTUPINFOA startup;
1684 DWORD code;
1686 /* let's start simplistic */
1687 memset(&startup, 0, sizeof(startup));
1688 startup.cb = sizeof(startup);
1689 startup.dwFlags = STARTF_USESHOWWINDOW;
1690 startup.wShowWindow = SW_SHOWNORMAL;
1692 get_file_name(resfile);
1693 sprintf(buffer, "\"%s\" process dump \"%s\" exit_code", selfname, resfile);
1694 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1696 /* not wait_child_process() because of the exit code */
1697 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1699 reload_child_info(resfile);
1700 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1701 okChildInt("ExitCode", "value", code);
1703 release_memory();
1704 DeleteFileA(resfile);
1707 static void test_OpenProcess(void)
1709 HANDLE hproc;
1710 void *addr1;
1711 MEMORY_BASIC_INFORMATION info;
1712 SIZE_T dummy, read_bytes;
1713 BOOL ret;
1715 /* without PROCESS_VM_OPERATION */
1716 hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1717 ok(hproc != NULL, "OpenProcess error %ld\n", GetLastError());
1719 SetLastError(0xdeadbeef);
1720 addr1 = VirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1721 ok(!addr1, "VirtualAllocEx should fail\n");
1722 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1723 { /* Win9x */
1724 CloseHandle(hproc);
1725 win_skip("VirtualAllocEx not implemented\n");
1726 return;
1728 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1730 read_bytes = 0xdeadbeef;
1731 SetLastError(0xdeadbeef);
1732 ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes);
1733 ok(ret, "ReadProcessMemory error %ld\n", GetLastError());
1734 ok(read_bytes == sizeof(dummy), "wrong read bytes %Id\n", read_bytes);
1736 CloseHandle(hproc);
1738 hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1739 ok(hproc != NULL, "OpenProcess error %ld\n", GetLastError());
1741 addr1 = VirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1742 ok(addr1 != NULL, "VirtualAllocEx error %ld\n", GetLastError());
1744 /* without PROCESS_QUERY_INFORMATION */
1745 SetLastError(0xdeadbeef);
1746 ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1747 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1748 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1750 /* without PROCESS_VM_READ */
1751 read_bytes = 0xdeadbeef;
1752 SetLastError(0xdeadbeef);
1753 ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1754 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1755 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1756 ok(read_bytes == 0, "wrong read bytes %Id\n", read_bytes);
1758 CloseHandle(hproc);
1760 hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1762 memset(&info, 0xcc, sizeof(info));
1763 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1764 ok(read_bytes == sizeof(info), "VirtualQueryEx error %ld\n", GetLastError());
1766 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1767 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1768 ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect);
1769 ok(info.RegionSize == 0x10000, "%Ix != 0x10000\n", info.RegionSize);
1770 ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State);
1771 /* NT reports Protect == 0 for a not committed memory block */
1772 ok(info.Protect == 0 /* NT */ ||
1773 info.Protect == PAGE_NOACCESS, /* Win9x */
1774 "%lx != PAGE_NOACCESS\n", info.Protect);
1775 ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
1777 SetLastError(0xdeadbeef);
1778 ok(!VirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1779 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1780 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1782 CloseHandle(hproc);
1784 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1785 if (hproc)
1787 SetLastError(0xdeadbeef);
1788 memset(&info, 0xcc, sizeof(info));
1789 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1790 if (read_bytes) /* win8 */
1792 ok(read_bytes == sizeof(info), "VirtualQueryEx error %ld\n", GetLastError());
1793 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1794 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1795 ok(info.AllocationProtect == PAGE_NOACCESS, "%lx != PAGE_NOACCESS\n", info.AllocationProtect);
1796 ok(info.RegionSize == 0x10000, "%Ix != 0x10000\n", info.RegionSize);
1797 ok(info.State == MEM_RESERVE, "%lx != MEM_RESERVE\n", info.State);
1798 ok(info.Protect == 0, "%lx != PAGE_NOACCESS\n", info.Protect);
1799 ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
1801 else /* before win8 */
1802 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1804 SetLastError(0xdeadbeef);
1805 ok(!VirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1806 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1807 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %ld\n", GetLastError());
1809 CloseHandle(hproc);
1812 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1815 static void test_GetProcessVersion(void)
1817 static char cmdline[] = "winver.exe";
1818 PROCESS_INFORMATION pi;
1819 STARTUPINFOA si;
1820 DWORD ret;
1822 SetLastError(0xdeadbeef);
1823 ret = GetProcessVersion(0);
1824 ok(ret, "GetProcessVersion error %lu\n", GetLastError());
1826 SetLastError(0xdeadbeef);
1827 ret = GetProcessVersion(GetCurrentProcessId());
1828 ok(ret, "GetProcessVersion error %lu\n", GetLastError());
1830 memset(&si, 0, sizeof(si));
1831 si.cb = sizeof(si);
1832 si.dwFlags = STARTF_USESHOWWINDOW;
1833 si.wShowWindow = SW_HIDE;
1834 SetLastError(0xdeadbeef);
1835 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1836 ok(ret, "CreateProcess error %lu\n", GetLastError());
1838 SetLastError(0xdeadbeef);
1839 ret = GetProcessVersion(pi.dwProcessId);
1840 ok(ret, "GetProcessVersion error %lu\n", GetLastError());
1842 SetLastError(0xdeadbeef);
1843 ret = TerminateProcess(pi.hProcess, 0);
1844 ok(ret, "TerminateProcess error %lu\n", GetLastError());
1846 CloseHandle(pi.hProcess);
1847 CloseHandle(pi.hThread);
1850 static void test_GetProcessImageFileNameA(void)
1852 DWORD rc;
1853 CHAR process[MAX_PATH];
1854 static const char harddisk[] = "\\Device\\HarddiskVolume";
1856 if (!pK32GetProcessImageFileNameA)
1858 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1859 return;
1862 /* callers must guess the buffer size */
1863 SetLastError(0xdeadbeef);
1864 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1865 ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1866 "K32GetProcessImageFileNameA(no buffer): returned %lu, le=%lu\n", rc, GetLastError());
1868 *process = '\0';
1869 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1870 expect_eq_d(rc, lstrlenA(process));
1871 if (strncmp(process, harddisk, lstrlenA(harddisk)))
1873 todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1874 return;
1877 if (!pQueryFullProcessImageNameA)
1878 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1879 else
1881 CHAR image[MAX_PATH];
1882 DWORD length;
1884 length = sizeof(image);
1885 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1886 expect_eq_d(length, lstrlenA(image));
1887 ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1891 static void test_QueryFullProcessImageNameA(void)
1893 #define INIT_STR "Just some words"
1894 DWORD length, size;
1895 CHAR buf[MAX_PATH], module[MAX_PATH];
1897 if (!pQueryFullProcessImageNameA)
1899 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1900 return;
1903 *module = '\0';
1904 SetLastError(0); /* old Windows don't reset it on success */
1905 size = GetModuleFileNameA(NULL, module, sizeof(module));
1906 ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %lu le=%lu\n", size, GetLastError());
1908 /* get the buffer length without \0 terminator */
1909 length = sizeof(buf);
1910 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1911 expect_eq_d(length, lstrlenA(buf));
1912 ok((buf[0] == '\\' && buf[1] == '\\') ||
1913 lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1915 /* when the buffer is too small
1916 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1917 * - the size variable is not modified
1918 * tested with the biggest too small size
1920 size = length;
1921 sprintf(buf,INIT_STR);
1922 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1923 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1924 expect_eq_d(length, size);
1925 expect_eq_s(INIT_STR, buf);
1927 /* retest with smaller buffer size
1929 size = 4;
1930 sprintf(buf,INIT_STR);
1931 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1932 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1933 expect_eq_d(4, size);
1934 expect_eq_s(INIT_STR, buf);
1936 /* this is a difference between the ansi and the unicode version
1937 * the unicode version crashes when the size is big enough to hold
1938 * the result while the ansi version throws an error
1940 size = 1024;
1941 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1942 expect_eq_d(1024, size);
1943 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
1946 static void test_QueryFullProcessImageNameW(void)
1948 HANDLE hSelf;
1949 WCHAR module_name[1024], device[1024];
1950 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
1951 WCHAR buf[1024];
1952 DWORD size, len;
1953 DWORD flags;
1955 if (!pQueryFullProcessImageNameW)
1957 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1958 return;
1961 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1963 /* GetCurrentProcess pseudo-handle */
1964 size = ARRAY_SIZE(buf);
1965 expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
1966 expect_eq_d(lstrlenW(buf), size);
1967 expect_eq_ws_i(buf, module_name);
1969 hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1970 /* Real handle */
1971 size = ARRAY_SIZE(buf);
1972 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1973 expect_eq_d(lstrlenW(buf), size);
1974 expect_eq_ws_i(buf, module_name);
1976 /* Buffer too small */
1977 size = lstrlenW(module_name)/2;
1978 lstrcpyW(buf, deviceW);
1979 SetLastError(0xdeadbeef);
1980 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1981 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
1982 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1983 expect_eq_ws_i(deviceW, buf); /* buffer not changed */
1985 /* Too small - not space for NUL terminator */
1986 size = lstrlenW(module_name);
1987 SetLastError(0xdeadbeef);
1988 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1989 expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
1990 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1992 /* NULL buffer */
1993 size = 0;
1994 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
1995 expect_eq_d(0, size);
1996 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1998 /* Buffer too small */
1999 size = lstrlenW(module_name)/2;
2000 SetLastError(0xdeadbeef);
2001 lstrcpyW(buf, module_name);
2002 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2003 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2004 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2005 expect_eq_ws_i(module_name, buf); /* buffer not changed */
2007 /* Invalid flags - a few arbitrary values only */
2008 for (flags = 2; flags <= 15; ++flags)
2010 size = ARRAY_SIZE(buf);
2011 SetLastError(0xdeadbeef);
2012 *(DWORD*)buf = 0x13579acf;
2013 todo_wine
2015 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, flags, buf, &size));
2016 expect_eq_d((DWORD)ARRAY_SIZE(buf), size); /* size not changed */
2017 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
2018 expect_eq_d(0x13579acf, *(DWORD*)buf); /* buffer not changed */
2021 for (flags = 16; flags != 0; flags <<= 1)
2023 size = ARRAY_SIZE(buf);
2024 SetLastError(0xdeadbeef);
2025 *(DWORD*)buf = 0x13579acf;
2026 todo_wine
2028 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, flags, buf, &size));
2029 expect_eq_d((DWORD)ARRAY_SIZE(buf), size); /* size not changed */
2030 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
2031 expect_eq_d(0x13579acf, *(DWORD*)buf); /* buffer not changed */
2035 /* native path */
2036 size = ARRAY_SIZE(buf);
2037 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2038 expect_eq_d(lstrlenW(buf), size);
2039 ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2040 ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2042 module_name[2] = '\0';
2043 *device = '\0';
2044 size = QueryDosDeviceW(module_name, device, ARRAY_SIZE(device));
2045 ok(size, "QueryDosDeviceW failed: le=%lu\n", GetLastError());
2046 len = lstrlenW(device);
2047 ok(size >= len+2, "expected %ld to be greater than %ld+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2049 if (size >= lstrlenW(buf))
2051 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2053 else
2055 ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2056 buf[len] = '\0';
2057 ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2058 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));
2061 CloseHandle(hSelf);
2064 static void test_Handles(void)
2066 HANDLE handle = GetCurrentProcess();
2067 HANDLE h2, h3;
2068 BOOL ret;
2069 DWORD code;
2071 ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2072 handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2073 "invalid current process handle %p\n", handle );
2074 ret = GetExitCodeProcess( handle, &code );
2075 ok( ret, "GetExitCodeProcess failed err %lu\n", GetLastError() );
2076 #ifdef _WIN64
2077 /* truncated handle */
2078 SetLastError( 0xdeadbeef );
2079 handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2080 ret = GetExitCodeProcess( handle, &code );
2081 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2082 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() );
2083 /* sign-extended handle */
2084 SetLastError( 0xdeadbeef );
2085 handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle);
2086 ret = GetExitCodeProcess( handle, &code );
2087 ok( ret, "GetExitCodeProcess failed err %lu\n", GetLastError() );
2088 /* invalid high-word */
2089 SetLastError( 0xdeadbeef );
2090 handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2091 ret = GetExitCodeProcess( handle, &code );
2092 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2093 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %lu\n", GetLastError() );
2094 #endif
2096 handle = GetStdHandle( STD_ERROR_HANDLE );
2097 ok( handle != 0, "handle %p\n", handle );
2098 DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &h3,
2099 0, TRUE, DUPLICATE_SAME_ACCESS );
2100 SetStdHandle( STD_ERROR_HANDLE, h3 );
2101 CloseHandle( (HANDLE)STD_ERROR_HANDLE );
2102 h2 = GetStdHandle( STD_ERROR_HANDLE );
2103 ok( h2 == 0 ||
2104 broken( h2 == h3) || /* nt4, w2k */
2105 broken( h2 == INVALID_HANDLE_VALUE), /* win9x */
2106 "wrong handle %p/%p\n", h2, h3 );
2107 SetStdHandle( STD_ERROR_HANDLE, handle );
2110 static void test_IsWow64Process(void)
2112 PROCESS_INFORMATION pi;
2113 STARTUPINFOA si;
2114 DWORD ret;
2115 BOOL is_wow64;
2116 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2117 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2119 if (!pIsWow64Process)
2121 win_skip("IsWow64Process is not available\n");
2122 return;
2125 memset(&si, 0, sizeof(si));
2126 si.cb = sizeof(si);
2127 si.dwFlags = STARTF_USESHOWWINDOW;
2128 si.wShowWindow = SW_HIDE;
2129 ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2130 if (ret)
2132 trace("Created process %s\n", cmdline_wow64);
2133 is_wow64 = FALSE;
2134 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2135 ok(ret, "IsWow64Process failed.\n");
2136 ok(is_wow64, "is_wow64 returned FALSE.\n");
2138 ret = TerminateProcess(pi.hProcess, 0);
2139 ok(ret, "TerminateProcess error\n");
2141 CloseHandle(pi.hProcess);
2142 CloseHandle(pi.hThread);
2145 memset(&si, 0, sizeof(si));
2146 si.cb = sizeof(si);
2147 si.dwFlags = STARTF_USESHOWWINDOW;
2148 si.wShowWindow = SW_HIDE;
2149 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2150 if (ret)
2152 trace("Created process %s\n", cmdline);
2153 is_wow64 = TRUE;
2154 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2155 ok(ret, "IsWow64Process failed.\n");
2156 ok(!is_wow64, "is_wow64 returned TRUE.\n");
2158 ret = TerminateProcess(pi.hProcess, 0);
2159 ok(ret, "TerminateProcess error\n");
2161 CloseHandle(pi.hProcess);
2162 CloseHandle(pi.hThread);
2166 static void test_IsWow64Process2(void)
2168 PROCESS_INFORMATION pi;
2169 STARTUPINFOA si;
2170 BOOL ret, is_wow64;
2171 USHORT machine, native_machine;
2172 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2173 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2174 #ifdef __i386__
2175 USHORT expect_native = IMAGE_FILE_MACHINE_I386;
2176 #elif defined __x86_64__
2177 USHORT expect_native = IMAGE_FILE_MACHINE_AMD64;
2178 #elif defined __arm__
2179 USHORT expect_native = IMAGE_FILE_MACHINE_ARMNT;
2180 #elif defined __aarch64__
2181 USHORT expect_native = IMAGE_FILE_MACHINE_ARM64;
2182 #else
2183 USHORT expect_native = 0;
2184 #endif
2186 if (!pIsWow64Process2)
2188 win_skip("IsWow64Process2 is not available\n");
2189 return;
2192 memset(&si, 0, sizeof(si));
2193 si.cb = sizeof(si);
2194 SetLastError(0xdeadbeef);
2195 ret = CreateProcessA(cmdline_wow64, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2196 if (ret)
2198 SetLastError(0xdeadbeef);
2199 machine = native_machine = 0xdead;
2200 ret = pIsWow64Process2(pi.hProcess, &machine, &native_machine);
2201 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2203 #if defined(__i386__) || defined(__x86_64__)
2204 ok(machine == IMAGE_FILE_MACHINE_I386, "got %#x\n", machine);
2205 ok( native_machine == IMAGE_FILE_MACHINE_AMD64 ||
2206 native_machine == IMAGE_FILE_MACHINE_ARM64, "got %#x\n", native_machine);
2207 expect_native = native_machine;
2208 #else
2209 skip("not supported architecture\n");
2210 #endif
2211 ret = TerminateProcess(pi.hProcess, 0);
2212 ok(ret, "TerminateProcess error\n");
2214 CloseHandle(pi.hProcess);
2215 CloseHandle(pi.hThread);
2218 memset(&si, 0, sizeof(si));
2219 si.cb = sizeof(si);
2220 SetLastError(0xdeadbeef);
2221 ret = CreateProcessA(cmdline, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2222 ok(ret, "CreateProcess error %lu\n", GetLastError());
2224 SetLastError(0xdeadbeef);
2225 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2226 ok(ret, "IsWow64Process error %lu\n", GetLastError());
2228 SetLastError(0xdeadbeef);
2229 machine = native_machine = 0xdead;
2230 ret = pIsWow64Process2(pi.hProcess, &machine, &native_machine);
2231 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2233 ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine);
2234 ok(native_machine == expect_native, "got %#x\n", native_machine);
2236 SetLastError(0xdeadbeef);
2237 machine = 0xdead;
2238 ret = pIsWow64Process2(pi.hProcess, &machine, NULL);
2239 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2240 ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine);
2242 ret = TerminateProcess(pi.hProcess, 0);
2243 ok(ret, "TerminateProcess error\n");
2245 CloseHandle(pi.hProcess);
2246 CloseHandle(pi.hThread);
2248 SetLastError(0xdeadbeef);
2249 ret = pIsWow64Process(GetCurrentProcess(), &is_wow64);
2250 ok(ret, "IsWow64Process error %lu\n", GetLastError());
2252 SetLastError(0xdeadbeef);
2253 machine = native_machine = 0xdead;
2254 ret = pIsWow64Process2(GetCurrentProcess(), &machine, &native_machine);
2255 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2257 if (is_wow64)
2259 ok(machine == IMAGE_FILE_MACHINE_I386, "got %#x\n", machine);
2260 ok(native_machine == expect_native, "got %#x\n", native_machine);
2262 else
2264 ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine);
2265 ok(native_machine == expect_native, "got %#x\n", native_machine);
2268 SetLastError(0xdeadbeef);
2269 machine = 0xdead;
2270 ret = pIsWow64Process2(GetCurrentProcess(), &machine, NULL);
2271 ok(ret, "IsWow64Process2 error %lu\n", GetLastError());
2272 if (is_wow64)
2273 ok(machine == IMAGE_FILE_MACHINE_I386, "got %#x\n", machine);
2274 else
2275 ok(machine == IMAGE_FILE_MACHINE_UNKNOWN, "got %#x\n", machine);
2278 static void test_SystemInfo(void)
2280 SYSTEM_INFO si, nsi;
2281 BOOL is_wow64;
2282 USHORT machine, native_machine;
2284 if (!pGetNativeSystemInfo)
2286 win_skip("GetNativeSystemInfo is not available\n");
2287 return;
2290 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2292 GetSystemInfo(&si);
2293 pGetNativeSystemInfo(&nsi);
2294 if (is_wow64)
2296 if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2298 ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2299 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2300 S(U(nsi)).wProcessorArchitecture);
2301 if (pIsWow64Process2 && pIsWow64Process2(GetCurrentProcess(), &machine, &native_machine) &&
2302 native_machine == IMAGE_FILE_MACHINE_ARM64)
2304 ok(nsi.dwProcessorType == PROCESSOR_INTEL_PENTIUM, "got %ld\n", nsi.dwProcessorType);
2305 ok(nsi.wProcessorLevel == 15, "got %d\n", nsi.wProcessorLevel);
2306 ok(nsi.wProcessorRevision == 0x40a, "got %d\n", nsi.wProcessorRevision);
2308 else ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664, "got %ld\n", nsi.dwProcessorType);
2311 else
2313 ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2314 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2315 S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2316 ok(si.dwProcessorType == nsi.dwProcessorType,
2317 "Expected no difference for dwProcessorType, got %ld and %ld\n",
2318 si.dwProcessorType, nsi.dwProcessorType);
2322 static void test_ProcessorCount(void)
2324 DWORD active, maximum;
2326 if (!pGetActiveProcessorCount || !pGetMaximumProcessorCount)
2328 win_skip("GetActiveProcessorCount or GetMaximumProcessorCount is not available\n");
2329 return;
2332 active = pGetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
2333 maximum = pGetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
2334 ok(active <= maximum,
2335 "Number of active processors %li is greater than maximum number of processors %li\n",
2336 active, maximum);
2339 static void test_RegistryQuota(void)
2341 BOOL ret;
2342 DWORD max_quota, used_quota;
2344 if (!pGetSystemRegistryQuota)
2346 win_skip("GetSystemRegistryQuota is not available\n");
2347 return;
2350 ret = pGetSystemRegistryQuota(NULL, NULL);
2351 ok(ret == TRUE,
2352 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2354 ret = pGetSystemRegistryQuota(&max_quota, NULL);
2355 ok(ret == TRUE,
2356 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2358 ret = pGetSystemRegistryQuota(NULL, &used_quota);
2359 ok(ret == TRUE,
2360 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2362 ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2363 ok(ret == TRUE,
2364 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2367 static void test_TerminateProcess(void)
2369 static char cmdline[] = "winver.exe";
2370 PROCESS_INFORMATION pi;
2371 STARTUPINFOA si;
2372 DWORD ret;
2373 HANDLE dummy, thread;
2375 memset(&si, 0, sizeof(si));
2376 si.cb = sizeof(si);
2377 SetLastError(0xdeadbeef);
2378 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2379 ok(ret, "CreateProcess error %lu\n", GetLastError());
2381 SetLastError(0xdeadbeef);
2382 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2383 ok(thread != 0, "CreateRemoteThread error %ld\n", GetLastError());
2385 /* create a not closed thread handle duplicate in the target process */
2386 SetLastError(0xdeadbeef);
2387 ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy,
2388 0, FALSE, DUPLICATE_SAME_ACCESS);
2389 ok(ret, "DuplicateHandle error %lu\n", GetLastError());
2391 SetLastError(0xdeadbeef);
2392 ret = TerminateThread(thread, 0);
2393 ok(ret, "TerminateThread error %lu\n", GetLastError());
2394 CloseHandle(thread);
2396 SetLastError(0xdeadbeef);
2397 ret = TerminateProcess(pi.hProcess, 0);
2398 ok(ret, "TerminateProcess error %lu\n", GetLastError());
2400 CloseHandle(pi.hProcess);
2401 CloseHandle(pi.hThread);
2404 static void test_DuplicateHandle(void)
2406 char path[MAX_PATH], file_name[MAX_PATH];
2407 HANDLE f, fmin, out;
2408 DWORD info;
2409 BOOL r;
2411 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2412 GetCurrentProcess(), &out, 0, FALSE,
2413 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2414 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2415 r = GetHandleInformation(out, &info);
2416 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2417 ok(info == 0, "info = %lx\n", info);
2418 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2419 CloseHandle(out);
2421 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2422 GetCurrentProcess(), &out, 0, TRUE,
2423 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2424 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2425 r = GetHandleInformation(out, &info);
2426 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2427 ok(info == HANDLE_FLAG_INHERIT, "info = %lx\n", info);
2428 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2429 CloseHandle(out);
2431 GetTempPathA(MAX_PATH, path);
2432 GetTempFileNameA(path, "wt", 0, file_name);
2433 f = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2434 if (f == INVALID_HANDLE_VALUE)
2436 ok(0, "could not create %s\n", file_name);
2437 return;
2440 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2441 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2442 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2443 ok(f == out, "f != out\n");
2444 r = GetHandleInformation(out, &info);
2445 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2446 ok(info == 0, "info = %lx\n", info);
2448 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2449 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2450 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2451 ok(f == out, "f != out\n");
2452 r = GetHandleInformation(out, &info);
2453 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2454 ok(info == HANDLE_FLAG_INHERIT, "info = %lx\n", info);
2456 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
2457 ok(r, "SetHandleInformation error %lu\n", GetLastError());
2458 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2459 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2460 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2461 ok(f != out, "f == out\n");
2462 r = GetHandleInformation(out, &info);
2463 ok(r, "GetHandleInformation error %lu\n", GetLastError());
2464 ok(info == HANDLE_FLAG_INHERIT, "info = %lx\n", info);
2465 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2466 ok(r, "SetHandleInformation error %lu\n", GetLastError());
2468 /* Test if DuplicateHandle allocates first free handle */
2469 if (f > out)
2471 fmin = out;
2473 else
2475 fmin = f;
2476 f = out;
2478 CloseHandle(fmin);
2479 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2480 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2481 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2482 ok(f == out, "f != out\n");
2483 CloseHandle(out);
2484 DeleteFileA(file_name);
2486 f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2487 ok(f != INVALID_HANDLE_VALUE, "Failed to open CONIN$ %lu\n", GetLastError());
2488 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2489 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2490 ok(r, "DuplicateHandle error %lu\n", GetLastError());
2491 ok(f == out || broken(/* Win7 */ (((ULONG_PTR)f & 3) == 3) && (f != out)), "f != out\n");
2492 CloseHandle(out);
2495 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2496 static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2498 LPOVERLAPPED overlapped;
2499 ULONG_PTR value;
2500 DWORD key;
2501 BOOL ret;
2503 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait);
2505 ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
2506 if (ret)
2508 ok_(__FILE__, line)(key == ekey, "unexpected key %lx\n", key);
2509 ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2510 ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2514 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2515 static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2517 BOOL ret;
2518 char buffer[MAX_PATH + 19];
2519 STARTUPINFOA si = {0};
2521 sprintf(buffer, "\"%s\" process %s", selfname, command);
2523 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2524 ok_(__FILE__, line)(ret, "CreateProcess error %lu\n", GetLastError());
2528 static void test_IsProcessInJob(void)
2530 HANDLE job, job2;
2531 PROCESS_INFORMATION pi;
2532 BOOL ret, out;
2534 if (!pIsProcessInJob)
2536 win_skip("IsProcessInJob not available.\n");
2537 return;
2540 job = pCreateJobObjectW(NULL, NULL);
2541 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2543 job2 = pCreateJobObjectW(NULL, NULL);
2544 ok(job2 != NULL, "CreateJobObject error %lu\n", GetLastError());
2546 create_process("wait", &pi);
2548 out = TRUE;
2549 ret = pIsProcessInJob(pi.hProcess, job, &out);
2550 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2551 ok(!out, "IsProcessInJob returned out=%u\n", out);
2553 out = TRUE;
2554 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2555 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2556 ok(!out, "IsProcessInJob returned out=%u\n", out);
2558 ret = pAssignProcessToJobObject(job, pi.hProcess);
2559 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2561 out = FALSE;
2562 ret = pIsProcessInJob(pi.hProcess, job, &out);
2563 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2564 ok(out, "IsProcessInJob returned out=%u\n", out);
2566 out = TRUE;
2567 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2568 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2569 ok(!out, "IsProcessInJob returned out=%u\n", out);
2571 out = FALSE;
2572 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2573 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2574 ok(out, "IsProcessInJob returned out=%u\n", out);
2576 TerminateProcess(pi.hProcess, 0);
2577 wait_child_process(pi.hProcess);
2579 out = FALSE;
2580 ret = pIsProcessInJob(pi.hProcess, job, &out);
2581 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2582 ok(out, "IsProcessInJob returned out=%u\n", out);
2584 CloseHandle(pi.hProcess);
2585 CloseHandle(pi.hThread);
2586 CloseHandle(job);
2587 CloseHandle(job2);
2590 static void test_TerminateJobObject(void)
2592 HANDLE job;
2593 PROCESS_INFORMATION pi;
2594 BOOL ret;
2595 DWORD dwret;
2597 job = pCreateJobObjectW(NULL, NULL);
2598 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2600 create_process("wait", &pi);
2602 ret = pAssignProcessToJobObject(job, pi.hProcess);
2603 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2605 ret = pTerminateJobObject(job, 123);
2606 ok(ret, "TerminateJobObject error %lu\n", GetLastError());
2608 /* not wait_child_process() because of the exit code */
2609 dwret = WaitForSingleObject(pi.hProcess, 1000);
2610 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret);
2611 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2613 ret = GetExitCodeProcess(pi.hProcess, &dwret);
2614 ok(ret, "GetExitCodeProcess error %lu\n", GetLastError());
2615 ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
2616 "wrong exitcode %lu\n", dwret);
2618 CloseHandle(pi.hProcess);
2619 CloseHandle(pi.hThread);
2621 /* Test adding an already terminated process to a job object */
2622 create_process("exit", &pi);
2623 wait_child_process(pi.hProcess);
2625 SetLastError(0xdeadbeef);
2626 ret = pAssignProcessToJobObject(job, pi.hProcess);
2627 ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2628 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2630 CloseHandle(pi.hProcess);
2631 CloseHandle(pi.hThread);
2633 CloseHandle(job);
2636 static void test_QueryInformationJobObject(void)
2638 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2639 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2640 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2641 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2642 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting_info;
2643 DWORD ret_len;
2644 PROCESS_INFORMATION pi[2];
2645 char buffer[50];
2646 HANDLE job, sem;
2647 BOOL ret;
2649 job = pCreateJobObjectW(NULL, NULL);
2650 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2652 /* Only active processes are returned */
2653 sprintf(buffer, "sync kernel32-process-%lx", GetCurrentProcessId());
2654 sem = CreateSemaphoreA(NULL, 0, 1, buffer + 5);
2655 ok(sem != NULL, "CreateSemaphoreA failed le=%lu\n", GetLastError());
2656 create_process(buffer, &pi[0]);
2658 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2659 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2661 ReleaseSemaphore(sem, 1, NULL);
2662 wait_and_close_child_process(&pi[0]);
2664 create_process("wait", &pi[0]);
2665 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2666 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2668 create_process("wait", &pi[1]);
2669 ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2670 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2672 SetLastError(0xdeadbeef);
2673 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2674 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len);
2675 ok(!ret, "QueryInformationJobObject expected failure\n");
2676 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2678 SetLastError(0xdeadbeef);
2679 memset(buf, 0, sizeof(buf));
2680 pid_list->NumberOfAssignedProcesses = 42;
2681 pid_list->NumberOfProcessIdsInList = 42;
2682 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2683 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len);
2684 ok(!ret, "QueryInformationJobObject expected failure\n");
2685 expect_eq_d(ERROR_MORE_DATA, GetLastError());
2686 if (ret)
2688 expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2689 expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2692 memset(buf, 0, sizeof(buf));
2693 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2694 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
2695 if(ret)
2697 if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2698 win_skip("Number of assigned processes broken on Win 8\n");
2699 else
2701 ULONG_PTR *list = pid_list->ProcessIdList;
2703 ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]),
2704 "QueryInformationJobObject returned ret_len=%lu\n", ret_len);
2706 expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2707 expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2708 expect_eq_d(pi[0].dwProcessId, list[0]);
2709 expect_eq_d(pi[1].dwProcessId, list[1]);
2713 /* test JobObjectBasicLimitInformation */
2714 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2715 sizeof(*basic_limit_info) - 1, &ret_len);
2716 ok(!ret, "QueryInformationJobObject expected failure\n");
2717 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2719 ret_len = 0xdeadbeef;
2720 memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2721 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2722 sizeof(*basic_limit_info), &ret_len);
2723 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
2724 ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%lu\n", ret_len);
2725 expect_eq_d(0, basic_limit_info->LimitFlags);
2727 /* test JobObjectExtendedLimitInformation */
2728 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2729 sizeof(ext_limit_info) - 1, &ret_len);
2730 ok(!ret, "QueryInformationJobObject expected failure\n");
2731 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2733 ret_len = 0xdeadbeef;
2734 memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2735 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2736 sizeof(ext_limit_info), &ret_len);
2737 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
2738 ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%lu\n", ret_len);
2739 expect_eq_d(0, basic_limit_info->LimitFlags);
2741 /* test JobObjectBasicAccountingInformation */
2742 ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting_info,
2743 sizeof(basic_accounting_info), &ret_len);
2744 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
2745 ok(ret_len == sizeof(basic_accounting_info), "QueryInformationJobObject returned ret_len=%lu\n", ret_len);
2746 expect_eq_d(3, basic_accounting_info.TotalProcesses);
2747 expect_eq_d(2, basic_accounting_info.ActiveProcesses);
2749 TerminateProcess(pi[0].hProcess, 0);
2750 CloseHandle(pi[0].hProcess);
2751 CloseHandle(pi[0].hThread);
2753 TerminateProcess(pi[1].hProcess, 0);
2754 CloseHandle(pi[1].hProcess);
2755 CloseHandle(pi[1].hThread);
2757 CloseHandle(job);
2760 static void test_CompletionPort(void)
2762 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
2763 PROCESS_INFORMATION pi, pi2;
2764 HANDLE job, port;
2765 BOOL ret;
2767 job = pCreateJobObjectW(NULL, NULL);
2768 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2770 create_process("wait", &pi2);
2771 ret = pAssignProcessToJobObject(job, pi2.hProcess);
2772 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2774 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2775 ok(port != NULL, "CreateIoCompletionPort error %lu\n", GetLastError());
2777 port_info.CompletionKey = job;
2778 port_info.CompletionPort = port;
2779 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2780 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
2782 create_process("wait", &pi);
2784 ret = pAssignProcessToJobObject(job, pi.hProcess);
2785 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2787 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi2.dwProcessId, 0);
2788 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2790 TerminateProcess(pi.hProcess, 0);
2791 wait_child_process(pi.hProcess);
2793 test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2794 TerminateProcess(pi2.hProcess, 0);
2795 wait_child_process(pi2.hProcess);
2796 CloseHandle(pi2.hProcess);
2797 CloseHandle(pi2.hThread);
2799 test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi2.dwProcessId, 0);
2800 test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100);
2802 CloseHandle(pi.hProcess);
2803 CloseHandle(pi.hThread);
2804 CloseHandle(job);
2805 CloseHandle(port);
2808 static void test_KillOnJobClose(void)
2810 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2811 PROCESS_INFORMATION pi;
2812 DWORD dwret;
2813 HANDLE job;
2814 BOOL ret;
2816 job = pCreateJobObjectW(NULL, NULL);
2817 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2819 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
2820 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2821 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2823 win_skip("Kill on job close limit not available\n");
2824 return;
2826 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
2828 create_process("wait", &pi);
2830 ret = pAssignProcessToJobObject(job, pi.hProcess);
2831 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2833 CloseHandle(job);
2835 /* not wait_child_process() for the kill */
2836 dwret = WaitForSingleObject(pi.hProcess, 1000);
2837 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret);
2838 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2840 CloseHandle(pi.hProcess);
2841 CloseHandle(pi.hThread);
2844 static void test_WaitForJobObject(void)
2846 HANDLE job, sem;
2847 char buffer[50];
2848 PROCESS_INFORMATION pi;
2849 BOOL ret;
2850 DWORD dwret;
2852 /* test waiting for a job object when the process is killed */
2853 job = pCreateJobObjectW(NULL, NULL);
2854 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2856 dwret = WaitForSingleObject(job, 100);
2857 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret);
2859 create_process("wait", &pi);
2861 ret = pAssignProcessToJobObject(job, pi.hProcess);
2862 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2864 dwret = WaitForSingleObject(job, 100);
2865 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret);
2867 ret = pTerminateJobObject(job, 123);
2868 ok(ret, "TerminateJobObject error %lu\n", GetLastError());
2870 dwret = WaitForSingleObject(job, 500);
2871 ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2872 "WaitForSingleObject returned %lu\n", dwret);
2874 if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2876 CloseHandle(pi.hProcess);
2877 CloseHandle(pi.hThread);
2878 CloseHandle(job);
2879 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2880 return;
2883 /* the object is not reset immediately */
2884 dwret = WaitForSingleObject(job, 100);
2885 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret);
2887 CloseHandle(pi.hProcess);
2888 CloseHandle(pi.hThread);
2890 /* creating a new process doesn't reset the signalled state */
2891 create_process("wait", &pi);
2893 ret = pAssignProcessToJobObject(job, pi.hProcess);
2894 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2896 dwret = WaitForSingleObject(job, 100);
2897 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", dwret);
2899 ret = pTerminateJobObject(job, 123);
2900 ok(ret, "TerminateJobObject error %lu\n", GetLastError());
2902 CloseHandle(pi.hProcess);
2903 CloseHandle(pi.hThread);
2905 CloseHandle(job);
2907 /* repeat the test, but this time the process terminates properly */
2908 job = pCreateJobObjectW(NULL, NULL);
2909 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2911 dwret = WaitForSingleObject(job, 100);
2912 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret);
2914 sprintf(buffer, "sync kernel32-process-%lx", GetCurrentProcessId());
2915 sem = CreateSemaphoreA(NULL, 0, 1, buffer + 5);
2916 ok(sem != NULL, "CreateSemaphoreA failed le=%lu\n", GetLastError());
2917 create_process(buffer, &pi);
2919 ret = pAssignProcessToJobObject(job, pi.hProcess);
2920 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2921 ReleaseSemaphore(sem, 1, NULL);
2923 dwret = WaitForSingleObject(job, 100);
2924 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %lu\n", dwret);
2926 wait_and_close_child_process(&pi);
2927 CloseHandle(job);
2928 CloseHandle(sem);
2931 static HANDLE test_AddSelfToJob(void)
2933 HANDLE job;
2934 BOOL ret;
2936 job = pCreateJobObjectW(NULL, NULL);
2937 ok(job != NULL, "CreateJobObject error %lu\n", GetLastError());
2939 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2940 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
2942 return job;
2945 static void test_jobInheritance(HANDLE job)
2947 PROCESS_INFORMATION pi;
2948 BOOL ret, out;
2950 if (!pIsProcessInJob)
2952 win_skip("IsProcessInJob not available.\n");
2953 return;
2956 create_process("exit", &pi);
2958 out = FALSE;
2959 ret = pIsProcessInJob(pi.hProcess, job, &out);
2960 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
2961 ok(out, "IsProcessInJob returned out=%u\n", out);
2963 wait_and_close_child_process(&pi);
2966 static void test_BreakawayOk(HANDLE parent_job)
2968 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2969 PROCESS_INFORMATION pi;
2970 STARTUPINFOA si = {0};
2971 char buffer[MAX_PATH + 23];
2972 BOOL ret, out, nested_jobs;
2973 HANDLE job;
2975 if (!pIsProcessInJob)
2977 win_skip("IsProcessInJob not available.\n");
2978 return;
2981 job = pCreateJobObjectW(NULL, NULL);
2982 ok(!!job, "CreateJobObjectW error %lu\n", GetLastError());
2984 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2985 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED) /* before Win 8. */,
2986 "AssignProcessToJobObject error %lu\n", GetLastError());
2987 nested_jobs = ret;
2988 if (!ret)
2989 win_skip("Nested jobs are not supported.\n");
2991 sprintf(buffer, "\"%s\" process exit", selfname);
2992 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2993 ok(!ret, "CreateProcessA expected failure\n");
2994 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2996 if (ret)
2998 TerminateProcess(pi.hProcess, 0);
2999 wait_and_close_child_process(&pi);
3002 if (nested_jobs)
3004 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
3005 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3006 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
3008 sprintf(buffer, "\"%s\" process exit", selfname);
3009 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
3010 ok(ret, "CreateProcessA error %lu\n", GetLastError());
3012 ret = pIsProcessInJob(pi.hProcess, job, &out);
3013 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3014 ok(!out, "IsProcessInJob returned out=%u\n", out);
3016 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
3017 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3018 ok(out, "IsProcessInJob returned out=%u\n", out);
3020 TerminateProcess(pi.hProcess, 0);
3021 wait_and_close_child_process(&pi);
3024 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
3025 ret = pSetInformationJobObject(parent_job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3026 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
3028 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
3029 ok(ret, "CreateProcessA error %lu\n", GetLastError());
3031 ret = pIsProcessInJob(pi.hProcess, job, &out);
3032 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3033 ok(!out, "IsProcessInJob returned out=%u\n", out);
3035 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
3036 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3037 ok(!out, "IsProcessInJob returned out=%u\n", out);
3039 wait_and_close_child_process(&pi);
3041 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
3042 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3043 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
3045 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3046 ok(ret, "CreateProcess error %lu\n", GetLastError());
3048 ret = pIsProcessInJob(pi.hProcess, job, &out);
3049 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
3050 ok(!out, "IsProcessInJob returned out=%u\n", out);
3052 wait_and_close_child_process(&pi);
3054 /* unset breakaway ok */
3055 limit_info.BasicLimitInformation.LimitFlags = 0;
3056 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3057 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
3060 static void test_StartupNoConsole(void)
3062 #ifndef _WIN64
3063 char buffer[2 * MAX_PATH + 25];
3064 STARTUPINFOA startup;
3065 PROCESS_INFORMATION info;
3067 memset(&startup, 0, sizeof(startup));
3068 startup.cb = sizeof(startup);
3069 startup.dwFlags = STARTF_USESHOWWINDOW;
3070 startup.wShowWindow = SW_SHOWNORMAL;
3071 get_file_name(resfile);
3072 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
3073 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3074 &info), "CreateProcess\n");
3075 wait_and_close_child_process(&info);
3077 reload_child_info(resfile);
3078 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3079 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3080 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3081 okChildInt("TEB", "hStdInput", 0);
3082 okChildInt("TEB", "hStdOutput", 0);
3083 okChildInt("TEB", "hStdError", 0);
3084 release_memory();
3085 DeleteFileA(resfile);
3086 #endif
3089 static void test_DetachConsoleHandles(void)
3091 #ifndef _WIN64
3092 char buffer[2 * MAX_PATH + 25];
3093 STARTUPINFOA startup;
3094 PROCESS_INFORMATION info;
3095 UINT result;
3097 memset(&startup, 0, sizeof(startup));
3098 startup.cb = sizeof(startup);
3099 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
3100 startup.wShowWindow = SW_SHOWNORMAL;
3101 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
3102 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
3103 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
3104 get_file_name(resfile);
3105 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
3106 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3107 &info), "CreateProcess\n");
3108 wait_and_close_child_process(&info);
3110 reload_child_info(resfile);
3111 result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile);
3112 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3113 result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile);
3114 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3115 result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile);
3116 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3117 result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile);
3118 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3119 result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile);
3120 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3121 result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile);
3122 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3124 release_memory();
3125 DeleteFileA(resfile);
3126 #endif
3129 #if defined(__i386__) || defined(__x86_64__)
3130 static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi,
3131 IMAGE_NT_HEADERS *nt_header)
3133 IMAGE_DOS_HEADER dos_header;
3135 if (!ReadProcessMemory(process_handle, mbi->BaseAddress, &dos_header, sizeof(dos_header), NULL))
3136 return FALSE;
3138 if ((dos_header.e_magic != IMAGE_DOS_SIGNATURE) ||
3139 ((ULONG)dos_header.e_lfanew > mbi->RegionSize) ||
3140 (dos_header.e_lfanew < sizeof(dos_header)))
3141 return FALSE;
3143 if (!ReadProcessMemory(process_handle, (char *)mbi->BaseAddress + dos_header.e_lfanew,
3144 nt_header, sizeof(*nt_header), NULL))
3145 return FALSE;
3147 return (nt_header->Signature == IMAGE_NT_SIGNATURE);
3150 static PVOID get_process_exe(HANDLE process_handle, IMAGE_NT_HEADERS *nt_header)
3152 PVOID exe_base, address;
3153 MEMORY_BASIC_INFORMATION mbi;
3155 /* Find the EXE base in the new process */
3156 exe_base = NULL;
3157 for (address = NULL ;
3158 VirtualQueryEx(process_handle, address, &mbi, sizeof(mbi)) ;
3159 address = (char *)mbi.BaseAddress + mbi.RegionSize) {
3160 if ((mbi.Type == SEC_IMAGE) &&
3161 read_nt_header(process_handle, &mbi, nt_header) &&
3162 !(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
3163 exe_base = mbi.BaseAddress;
3164 break;
3168 return exe_base;
3171 static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE_NT_HEADERS *nt_header)
3173 BOOL ret;
3174 IMAGE_IMPORT_DESCRIPTOR iid;
3175 ULONG_PTR orig_iat_entry_value, iat_entry_value;
3177 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, "Import table VA is zero\n");
3178 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, "Import table Size is zero\n");
3180 if (!nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ||
3181 !nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
3182 return FALSE;
3184 /* Read the first IID */
3185 ret = ReadProcessMemory(process_handle,
3186 (char *)module_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
3187 &iid, sizeof(iid), NULL);
3188 ok(ret, "Failed to read remote module IID (%ld)\n", GetLastError());
3190 /* Validate the IID is present and not a bound import, and that we have
3191 an OriginalFirstThunk to compare with */
3192 ok(iid.Name, "Module first IID does not have a Name\n");
3193 ok(iid.FirstThunk, "Module first IID does not have a FirstThunk\n");
3194 ok(!iid.TimeDateStamp, "Module first IID is a bound import (UNSUPPORTED for current test)\n");
3195 ok(iid.OriginalFirstThunk, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3197 /* Read a single IAT entry from the FirstThunk */
3198 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.FirstThunk,
3199 &iat_entry_value, sizeof(iat_entry_value), NULL);
3200 ok(ret, "Failed to read IAT entry from FirstThunk (%ld)\n", GetLastError());
3201 ok(iat_entry_value, "IAT entry in FirstThunk is NULL\n");
3203 /* Read a single IAT entry from the OriginalFirstThunk */
3204 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.OriginalFirstThunk,
3205 &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL);
3206 ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%ld)\n", GetLastError());
3207 ok(orig_iat_entry_value, "IAT entry in OriginalFirstThunk is NULL\n");
3209 return iat_entry_value != orig_iat_entry_value;
3212 static void test_SuspendProcessNewThread(void)
3214 BOOL ret;
3215 STARTUPINFOA si = {0};
3216 PROCESS_INFORMATION pi = {0};
3217 PVOID exe_base, exit_thread_ptr;
3218 IMAGE_NT_HEADERS nt_header;
3219 HANDLE thread_handle = NULL;
3220 DWORD dret, exit_code = 0;
3221 CONTEXT ctx;
3223 exit_thread_ptr = GetProcAddress(hkernel32, "ExitThread");
3224 ok(exit_thread_ptr != NULL, "GetProcAddress ExitThread failed\n");
3226 si.cb = sizeof(si);
3227 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3228 ok(ret, "Failed to create process (%ld)\n", GetLastError());
3230 exe_base = get_process_exe(pi.hProcess, &nt_header);
3231 ok(exe_base != NULL, "Could not find EXE in remote process\n");
3233 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3234 ok(!ret, "IAT entry resolved prematurely\n");
3236 thread_handle = CreateRemoteThread(pi.hProcess, NULL, 0,
3237 (LPTHREAD_START_ROUTINE)exit_thread_ptr,
3238 (PVOID)(ULONG_PTR)0x1234, CREATE_SUSPENDED, NULL);
3239 ok(thread_handle != NULL, "Could not create remote thread (%ld)\n", GetLastError());
3241 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3242 ok(!ret, "IAT entry resolved prematurely\n");
3244 ctx.ContextFlags = CONTEXT_ALL;
3245 ret = GetThreadContext( thread_handle, &ctx );
3246 ok( ret, "Failed retrieving remote thread context (%ld)\n", GetLastError() );
3247 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %lx\n", ctx.ContextFlags );
3248 #ifdef __x86_64__
3249 ok( !ctx.Rax, "rax is not zero %Ix\n", ctx.Rax );
3250 ok( !ctx.Rbx, "rbx is not zero %Ix\n", ctx.Rbx );
3251 ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %Ix/%p\n", ctx.Rcx, exit_thread_ptr );
3252 ok( ctx.Rdx == 0x1234, "wrong rdx %Ix\n", ctx.Rdx );
3253 ok( !ctx.Rsi, "rsi is not zero %Ix\n", ctx.Rsi );
3254 ok( !ctx.Rdi, "rdi is not zero %Ix\n", ctx.Rdi );
3255 ok( !ctx.Rbp, "rbp is not zero %Ix\n", ctx.Rbp );
3256 ok( !ctx.R8, "r8 is not zero %Ix\n", ctx.R8 );
3257 ok( !ctx.R9, "r9 is not zero %Ix\n", ctx.R9 );
3258 ok( !ctx.R10, "r10 is not zero %Ix\n", ctx.R10 );
3259 ok( !ctx.R11, "r11 is not zero %Ix\n", ctx.R11 );
3260 ok( !ctx.R12, "r12 is not zero %Ix\n", ctx.R12 );
3261 ok( !ctx.R13, "r13 is not zero %Ix\n", ctx.R13 );
3262 ok( !ctx.R14, "r14 is not zero %Ix\n", ctx.R14 );
3263 ok( !ctx.R15, "r15 is not zero %Ix\n", ctx.R15 );
3264 ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %Ix\n", ctx.Rsp );
3265 ok( ctx.EFlags == 0x200, "wrong flags %08lx\n", ctx.EFlags );
3266 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08lx\n", ctx.MxCsr );
3267 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3268 #else
3269 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08lx\n", ctx.Ebp );
3270 if (!ctx.Ebp) /* winxp is completely different */
3272 ok( !ctx.Ecx, "ecx is not zero %08lx\n", ctx.Ecx );
3273 ok( !ctx.Edx, "edx is not zero %08lx\n", ctx.Edx );
3274 ok( !ctx.Esi, "esi is not zero %08lx\n", ctx.Esi );
3275 ok( !ctx.Edi, "edi is not zero %08lx\n", ctx.Edi );
3277 ok( ctx.Eax == (ULONG_PTR)exit_thread_ptr, "wrong eax %08lx/%p\n", ctx.Eax, exit_thread_ptr );
3278 ok( ctx.Ebx == 0x1234, "wrong ebx %08lx\n", ctx.Ebx );
3279 ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3280 "esp is not at top of stack page or properly aligned: %08lx\n", ctx.Esp );
3281 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08lx\n", ctx.EFlags );
3282 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08lx\n", ctx.FloatSave.ControlWord );
3283 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3284 #endif
3286 ResumeThread( thread_handle );
3287 dret = WaitForSingleObject(thread_handle, 60000);
3288 ok(dret == WAIT_OBJECT_0, "Waiting for remote thread failed (%ld)\n", GetLastError());
3289 ret = GetExitCodeThread(thread_handle, &exit_code);
3290 ok(ret, "Failed to retrieve remote thread exit code (%ld)\n", GetLastError());
3291 ok(exit_code == 0x1234, "Invalid remote thread exit code\n");
3293 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3294 ok(ret, "EXE IAT entry not resolved\n");
3296 if (thread_handle)
3297 CloseHandle(thread_handle);
3299 /* Note that the child's main thread is still suspended so the exit code
3300 * is set by the TerminateProcess() call.
3302 TerminateProcess(pi.hProcess, 0);
3303 wait_and_close_child_process(&pi);
3306 static void test_SuspendProcessState(void)
3308 struct pipe_params
3310 ULONG pipe_write_buf;
3311 ULONG pipe_read_buf;
3312 ULONG bytes_returned;
3313 CHAR pipe_name[MAX_PATH];
3316 #ifdef __x86_64__
3317 struct remote_rop_chain
3319 void *exit_process_ptr;
3320 ULONG_PTR home_rcx;
3321 ULONG_PTR home_rdx;
3322 ULONG_PTR home_r8;
3323 ULONG_PTR home_r9;
3324 ULONG_PTR pipe_read_buf_size;
3325 ULONG_PTR bytes_returned;
3326 ULONG_PTR timeout;
3328 #else
3329 struct remote_rop_chain
3331 void *exit_process_ptr;
3332 ULONG_PTR pipe_name;
3333 ULONG_PTR pipe_write_buf;
3334 ULONG_PTR pipe_write_buf_size;
3335 ULONG_PTR pipe_read_buf;
3336 ULONG_PTR pipe_read_buf_size;
3337 ULONG_PTR bytes_returned;
3338 ULONG_PTR timeout;
3339 void *unreached_ret;
3340 ULONG_PTR exit_code;
3342 #endif
3344 static const char pipe_name[] = "\\\\.\\pipe\\TestPipe";
3345 static const ULONG pipe_write_magic = 0x454e4957;
3346 STARTUPINFOA si = {0};
3347 PROCESS_INFORMATION pi = {0};
3348 PVOID exe_base, remote_pipe_params, exit_process_ptr,
3349 call_named_pipe_a;
3350 IMAGE_NT_HEADERS nt_header;
3351 struct pipe_params pipe_params;
3352 struct remote_rop_chain rop_chain;
3353 CONTEXT ctx;
3354 HANDLE server_pipe_handle;
3355 BOOL pipe_connected;
3356 ULONG pipe_magic, numb;
3357 BOOL ret;
3358 void *user_thread_start, *start_ptr, *entry_ptr, *peb_ptr;
3359 PEB child_peb, *peb = NtCurrentTeb()->Peb;
3361 exit_process_ptr = GetProcAddress(hkernel32, "ExitProcess");
3362 ok(exit_process_ptr != NULL, "GetProcAddress ExitProcess failed\n");
3364 call_named_pipe_a = GetProcAddress(hkernel32, "CallNamedPipeA");
3365 ok(call_named_pipe_a != NULL, "GetProcAddress CallNamedPipeA failed\n");
3367 si.cb = sizeof(si);
3368 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3369 ok(ret, "Failed to create process (%ld)\n", GetLastError());
3371 exe_base = get_process_exe(pi.hProcess, &nt_header);
3372 /* Make sure we found the EXE in the new process */
3373 ok(exe_base != NULL, "Could not find EXE in remote process\n");
3375 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3376 ok(!ret, "IAT entry resolved prematurely\n");
3378 server_pipe_handle = CreateNamedPipeA(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH,
3379 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0x20000, 0x20000,
3380 0, NULL);
3381 ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%ld)\n", GetLastError());
3383 /* Set up the remote process environment */
3384 ctx.ContextFlags = CONTEXT_ALL;
3385 ret = GetThreadContext(pi.hThread, &ctx);
3386 ok(ret, "Failed retrieving remote thread context (%ld)\n", GetLastError());
3387 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %lx\n", ctx.ContextFlags );
3389 remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE);
3390 ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%ld)\n", GetLastError());
3392 pipe_params.pipe_write_buf = pipe_write_magic;
3393 pipe_params.pipe_read_buf = 0;
3394 pipe_params.bytes_returned = 0;
3395 strcpy(pipe_params.pipe_name, pipe_name);
3397 ret = WriteProcessMemory(pi.hProcess, remote_pipe_params,
3398 &pipe_params, sizeof(pipe_params), NULL);
3399 ok(ret, "Failed to write to remote process memory (%ld)\n", GetLastError());
3401 #ifdef __x86_64__
3402 ok( !ctx.Rax, "rax is not zero %Ix\n", ctx.Rax );
3403 ok( !ctx.Rbx, "rbx is not zero %Ix\n", ctx.Rbx );
3404 ok( !ctx.Rsi, "rsi is not zero %Ix\n", ctx.Rsi );
3405 ok( !ctx.Rdi, "rdi is not zero %Ix\n", ctx.Rdi );
3406 ok( !ctx.Rbp, "rbp is not zero %Ix\n", ctx.Rbp );
3407 ok( !ctx.R8, "r8 is not zero %Ix\n", ctx.R8 );
3408 ok( !ctx.R9, "r9 is not zero %Ix\n", ctx.R9 );
3409 ok( !ctx.R10, "r10 is not zero %Ix\n", ctx.R10 );
3410 ok( !ctx.R11, "r11 is not zero %Ix\n", ctx.R11 );
3411 ok( !ctx.R12, "r12 is not zero %Ix\n", ctx.R12 );
3412 ok( !ctx.R13, "r13 is not zero %Ix\n", ctx.R13 );
3413 ok( !ctx.R14, "r14 is not zero %Ix\n", ctx.R14 );
3414 ok( !ctx.R15, "r15 is not zero %Ix\n", ctx.R15 );
3415 ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %Ix\n", ctx.Rsp );
3416 ok( ctx.EFlags == 0x200, "wrong flags %08lx\n", ctx.EFlags );
3417 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08lx\n", ctx.MxCsr );
3418 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3419 start_ptr = (void *)ctx.Rip;
3420 entry_ptr = (void *)ctx.Rcx;
3421 peb_ptr = (void *)ctx.Rdx;
3423 rop_chain.exit_process_ptr = exit_process_ptr;
3424 ctx.Rcx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3425 ctx.Rdx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3426 ctx.R8 = sizeof(pipe_params.pipe_write_buf);
3427 ctx.R9 = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3428 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3429 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3430 rop_chain.timeout = 10000;
3432 ctx.Rip = (ULONG_PTR)call_named_pipe_a;
3433 ctx.Rsp -= sizeof(rop_chain);
3434 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL);
3435 ok(ret, "Failed to write to remote process thread stack (%ld)\n", GetLastError());
3436 #else
3437 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08lx\n", ctx.Ebp );
3438 if (!ctx.Ebp) /* winxp is completely different */
3440 ok( !ctx.Ecx, "ecx is not zero %08lx\n", ctx.Ecx );
3441 ok( !ctx.Edx, "edx is not zero %08lx\n", ctx.Edx );
3442 ok( !ctx.Esi, "esi is not zero %08lx\n", ctx.Esi );
3443 ok( !ctx.Edi, "edi is not zero %08lx\n", ctx.Edi );
3445 ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3446 "esp is not at top of stack page or properly aligned: %08lx\n", ctx.Esp );
3447 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08lx\n", ctx.EFlags );
3448 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08lx\n", ctx.FloatSave.ControlWord );
3449 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3450 start_ptr = (void *)ctx.Eip;
3451 entry_ptr = (void *)ctx.Eax;
3452 peb_ptr = (void *)ctx.Ebx;
3454 rop_chain.exit_process_ptr = exit_process_ptr;
3455 rop_chain.pipe_name = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3456 rop_chain.pipe_write_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3457 rop_chain.pipe_write_buf_size = sizeof(pipe_params.pipe_write_buf);
3458 rop_chain.pipe_read_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3459 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3460 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3461 rop_chain.timeout = 10000;
3462 rop_chain.exit_code = 0;
3464 ctx.Eip = (ULONG_PTR)call_named_pipe_a;
3465 ctx.Esp -= sizeof(rop_chain);
3466 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Esp, &rop_chain, sizeof(rop_chain), NULL);
3467 ok(ret, "Failed to write to remote process thread stack (%ld)\n", GetLastError());
3468 #endif
3470 ret = ReadProcessMemory( pi.hProcess, peb_ptr, &child_peb, sizeof(child_peb), NULL );
3471 ok( ret, "Failed to read PEB (%lu)\n", GetLastError() );
3472 ok( child_peb.ImageBaseAddress == exe_base, "wrong base %p/%p\n",
3473 child_peb.ImageBaseAddress, exe_base );
3474 user_thread_start = GetProcAddress( GetModuleHandleA("ntdll.dll"), "RtlUserThreadStart" );
3475 if (user_thread_start)
3476 ok( start_ptr == user_thread_start,
3477 "wrong start addr %p / %p\n", start_ptr, user_thread_start );
3478 ok( entry_ptr == (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint,
3479 "wrong entry point %p/%p\n", entry_ptr,
3480 (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint );
3482 ok( !child_peb.LdrData, "LdrData set %p\n", child_peb.LdrData );
3483 ok( !child_peb.FastPebLock, "FastPebLock set %p\n", child_peb.FastPebLock );
3484 ok( !child_peb.TlsBitmap, "TlsBitmap set %p\n", child_peb.TlsBitmap );
3485 ok( !child_peb.TlsExpansionBitmap, "TlsExpansionBitmap set %p\n", child_peb.TlsExpansionBitmap );
3486 ok( !child_peb.LoaderLock, "LoaderLock set %p\n", child_peb.LoaderLock );
3487 ok( !child_peb.ProcessHeap, "ProcessHeap set %p\n", child_peb.ProcessHeap );
3488 ok( !child_peb.CSDVersion.Buffer, "CSDVersion set %s\n", debugstr_w(child_peb.CSDVersion.Buffer) );
3490 ok( child_peb.OSMajorVersion == peb->OSMajorVersion, "OSMajorVersion not set %lu\n", child_peb.OSMajorVersion );
3491 ok( child_peb.OSPlatformId == peb->OSPlatformId, "OSPlatformId not set %lu\n", child_peb.OSPlatformId );
3492 ok( child_peb.SessionId == peb->SessionId, "SessionId not set %lu\n", child_peb.SessionId );
3493 ok( child_peb.CriticalSectionTimeout.QuadPart, "CriticalSectionTimeout not set %s\n",
3494 wine_dbgstr_longlong(child_peb.CriticalSectionTimeout.QuadPart) );
3495 ok( child_peb.HeapSegmentReserve == peb->HeapSegmentReserve,
3496 "HeapSegmentReserve not set %Iu\n", child_peb.HeapSegmentReserve );
3497 ok( child_peb.HeapSegmentCommit == peb->HeapSegmentCommit,
3498 "HeapSegmentCommit not set %Iu\n", child_peb.HeapSegmentCommit );
3499 ok( child_peb.HeapDeCommitTotalFreeThreshold == peb->HeapDeCommitTotalFreeThreshold,
3500 "HeapDeCommitTotalFreeThreshold not set %Iu\n", child_peb.HeapDeCommitTotalFreeThreshold );
3501 ok( child_peb.HeapDeCommitFreeBlockThreshold == peb->HeapDeCommitFreeBlockThreshold,
3502 "HeapDeCommitFreeBlockThreshold not set %Iu\n", child_peb.HeapDeCommitFreeBlockThreshold );
3504 if (pNtQueryInformationThread)
3506 TEB child_teb;
3507 THREAD_BASIC_INFORMATION info;
3508 NTSTATUS status = pNtQueryInformationThread( pi.hThread, ThreadBasicInformation,
3509 &info, sizeof(info), NULL );
3510 ok( !status, "NtQueryInformationProcess failed %lx\n", status );
3511 ret = ReadProcessMemory( pi.hProcess, info.TebBaseAddress, &child_teb, sizeof(child_teb), NULL );
3512 ok( ret, "Failed to read TEB (%lu)\n", GetLastError() );
3514 ok( child_teb.Peb == peb_ptr, "wrong Peb %p / %p\n", child_teb.Peb, peb_ptr );
3515 ok( PtrToUlong(child_teb.ClientId.UniqueProcess) == pi.dwProcessId, "wrong pid %lx / %lx\n",
3516 PtrToUlong(child_teb.ClientId.UniqueProcess), pi.dwProcessId );
3517 ok( PtrToUlong(child_teb.ClientId.UniqueThread) == pi.dwThreadId, "wrong tid %lx / %lx\n",
3518 PtrToUlong(child_teb.ClientId.UniqueThread), pi.dwThreadId );
3519 ok( PtrToUlong(child_teb.RealClientId.UniqueProcess) == pi.dwProcessId, "wrong real pid %lx / %lx\n",
3520 PtrToUlong(child_teb.RealClientId.UniqueProcess), pi.dwProcessId );
3521 ok( PtrToUlong(child_teb.RealClientId.UniqueThread) == pi.dwThreadId, "wrong real tid %lx / %lx\n",
3522 PtrToUlong(child_teb.RealClientId.UniqueThread), pi.dwThreadId );
3523 ok( child_teb.StaticUnicodeString.MaximumLength == sizeof(child_teb.StaticUnicodeBuffer),
3524 "StaticUnicodeString.MaximumLength wrong %x\n", child_teb.StaticUnicodeString.MaximumLength );
3525 ok( (char *)child_teb.StaticUnicodeString.Buffer == (char *)info.TebBaseAddress + offsetof(TEB, StaticUnicodeBuffer),
3526 "StaticUnicodeString.Buffer wrong %p\n", child_teb.StaticUnicodeString.Buffer );
3528 ok( !child_teb.CurrentLocale, "CurrentLocale set %lx\n", child_teb.CurrentLocale );
3529 ok( !child_teb.TlsLinks.Flink, "TlsLinks.Flink set %p\n", child_teb.TlsLinks.Flink );
3530 ok( !child_teb.TlsLinks.Blink, "TlsLinks.Blink set %p\n", child_teb.TlsLinks.Blink );
3531 ok( !child_teb.TlsExpansionSlots, "TlsExpansionSlots set %p\n", child_teb.TlsExpansionSlots );
3532 ok( !child_teb.FlsSlots, "FlsSlots set %p\n", child_teb.FlsSlots );
3535 ret = SetThreadContext(pi.hThread, &ctx);
3536 ok(ret, "Failed to set remote thread context (%ld)\n", GetLastError());
3538 ResumeThread(pi.hThread);
3540 pipe_connected = ConnectNamedPipe(server_pipe_handle, NULL) || (GetLastError() == ERROR_PIPE_CONNECTED);
3541 ok(pipe_connected, "Pipe did not connect\n");
3543 ret = ReadFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3544 ok(ret, "Failed to read buffer from pipe (%ld)\n", GetLastError());
3546 ok(pipe_magic == pipe_write_magic, "Did not get the correct magic from the remote process\n");
3548 /* Validate the imports: at this point the thread in the new process
3549 * should have initialized the EXE module imports and called each dll's
3550 * DllMain(), notifying it of the new thread in the process.
3552 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3553 ok(ret, "EXE IAT is not resolved\n");
3555 ret = WriteFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3556 ok(ret, "Failed to write the magic back to the pipe (%ld)\n", GetLastError());
3557 CloseHandle(server_pipe_handle);
3559 /* Avoid wait_child_process() because the exit code results from a race
3560 * between the TerminateProcess() call and the child's ExitProcess() call
3561 * which uses a random value in the 64 bit case.
3563 TerminateProcess(pi.hProcess, 0);
3564 WaitForSingleObject(pi.hProcess, 10000);
3565 CloseHandle(pi.hProcess);
3566 CloseHandle(pi.hThread);
3568 #else
3569 static void test_SuspendProcessNewThread(void)
3572 static void test_SuspendProcessState(void)
3575 #endif
3577 static void test_DetachStdHandles(void)
3579 #ifndef _WIN64
3580 char buffer[2 * MAX_PATH + 25], tempfile[MAX_PATH];
3581 STARTUPINFOA startup;
3582 PROCESS_INFORMATION info;
3583 HANDLE hstdin, hstdout, hstderr, htemp;
3584 BOOL res;
3586 hstdin = GetStdHandle(STD_INPUT_HANDLE);
3587 hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
3588 hstderr = GetStdHandle(STD_ERROR_HANDLE);
3590 get_file_name(tempfile);
3591 htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3592 ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n");
3594 memset(&startup, 0, sizeof(startup));
3595 startup.cb = sizeof(startup);
3596 startup.dwFlags = STARTF_USESHOWWINDOW;
3597 startup.wShowWindow = SW_SHOWNORMAL;
3598 get_file_name(resfile);
3599 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, resfile);
3601 SetStdHandle(STD_INPUT_HANDLE, htemp);
3602 SetStdHandle(STD_OUTPUT_HANDLE, htemp);
3603 SetStdHandle(STD_ERROR_HANDLE, htemp);
3605 res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3606 &info);
3608 SetStdHandle(STD_INPUT_HANDLE, hstdin);
3609 SetStdHandle(STD_OUTPUT_HANDLE, hstdout);
3610 SetStdHandle(STD_ERROR_HANDLE, hstderr);
3612 ok(res, "CreateProcess failed\n");
3613 wait_and_close_child_process(&info);
3615 reload_child_info(resfile);
3616 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3617 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3618 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3619 okChildInt("TEB", "hStdInput", 0);
3620 okChildInt("TEB", "hStdOutput", 0);
3621 okChildInt("TEB", "hStdError", 0);
3622 release_memory();
3623 DeleteFileA(resfile);
3625 CloseHandle(htemp);
3626 DeleteFileA(tempfile);
3627 #endif
3630 static void test_GetNumaProcessorNode(void)
3632 SYSTEM_INFO si;
3633 UCHAR node;
3634 BOOL ret;
3635 int i;
3637 if (!pGetNumaProcessorNode)
3639 win_skip("GetNumaProcessorNode is missing\n");
3640 return;
3643 GetSystemInfo(&si);
3644 for (i = 0; i < 256; i++)
3646 SetLastError(0xdeadbeef);
3647 node = (i < si.dwNumberOfProcessors) ? 0xFF : 0xAA;
3648 ret = pGetNumaProcessorNode(i, &node);
3649 if (i < si.dwNumberOfProcessors)
3651 ok(ret, "GetNumaProcessorNode returned FALSE for processor %d\n", i);
3652 ok(node != 0xFF, "expected node != 0xFF, but got 0xFF\n");
3654 else
3656 ok(!ret, "GetNumaProcessorNode returned TRUE for processor %d\n", i);
3657 ok(node == 0xFF || broken(node == 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node);
3658 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
3663 static void test_session_info(void)
3665 DWORD session_id, active_session;
3666 BOOL r;
3668 r = ProcessIdToSessionId(GetCurrentProcessId(), &session_id);
3669 ok(r, "ProcessIdToSessionId failed: %lu\n", GetLastError());
3670 trace("session_id = %lx\n", session_id);
3672 active_session = pWTSGetActiveConsoleSessionId();
3673 trace("active_session = %lx\n", active_session);
3676 static void test_process_info(HANDLE hproc)
3678 char buf[4096];
3679 static const ULONG info_size[] =
3681 sizeof(PROCESS_BASIC_INFORMATION) /* ProcessBasicInformation */,
3682 sizeof(QUOTA_LIMITS) /* ProcessQuotaLimits */,
3683 sizeof(IO_COUNTERS) /* ProcessIoCounters */,
3684 sizeof(VM_COUNTERS) /* ProcessVmCounters */,
3685 sizeof(KERNEL_USER_TIMES) /* ProcessTimes */,
3686 sizeof(ULONG) /* ProcessBasePriority */,
3687 sizeof(ULONG) /* ProcessRaisePriority */,
3688 sizeof(HANDLE) /* ProcessDebugPort */,
3689 sizeof(HANDLE) /* ProcessExceptionPort */,
3690 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3691 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3692 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3693 sizeof(ULONG) /* ProcessDefaultHardErrorMode */,
3694 0 /* ProcessIoPortHandlers: kernel-mode only */,
3695 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3696 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3697 sizeof(ULONG) /* ProcessUserModeIOPL */,
3698 sizeof(BOOLEAN) /* ProcessEnableAlignmentFaultFixup */,
3699 sizeof(PROCESS_PRIORITY_CLASS) /* ProcessPriorityClass */,
3700 sizeof(ULONG) /* ProcessWx86Information */,
3701 sizeof(ULONG) /* ProcessHandleCount */,
3702 sizeof(ULONG_PTR) /* ProcessAffinityMask */,
3703 sizeof(ULONG) /* ProcessPriorityBoost */,
3704 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3705 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3706 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3707 sizeof(ULONG_PTR) /* ProcessWow64Information */,
3708 sizeof(buf) /* ProcessImageFileName */,
3709 sizeof(ULONG) /* ProcessLUIDDeviceMapsEnabled */,
3710 sizeof(ULONG) /* ProcessBreakOnTermination */,
3711 sizeof(HANDLE) /* ProcessDebugObjectHandle */,
3712 sizeof(ULONG) /* ProcessDebugFlags */,
3713 sizeof(buf) /* ProcessHandleTracing */,
3714 sizeof(ULONG) /* ProcessIoPriority */,
3715 sizeof(ULONG) /* ProcessExecuteFlags */,
3716 0 /* FIXME: sizeof(?) ProcessTlsInformation */,
3717 sizeof(ULONG) /* ProcessCookie */,
3718 sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */,
3719 sizeof(PROCESS_CYCLE_TIME_INFORMATION) /* ProcessCycleTime */,
3720 sizeof(ULONG) /* ProcessPagePriority */,
3721 40 /* ProcessInstrumentationCallback */,
3722 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
3723 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
3724 sizeof(buf) /* ProcessImageFileNameWin32 */,
3725 #if 0 /* FIXME: Add remaining classes */
3726 sizeof(HANDLE) /* ProcessImageFileMapping */,
3727 sizeof(PROCESS_AFFINITY_UPDATE_MODE) /* ProcessAffinityUpdateMode */,
3728 sizeof(PROCESS_MEMORY_ALLOCATION_MODE) /* ProcessMemoryAllocationMode */,
3729 sizeof(USHORT[]) /* ProcessGroupInformation */,
3730 sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */,
3731 sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */,
3732 sizeof(PROCESS_WINDOW_INFORMATION) /* ProcessWindowInformation */,
3733 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */,
3734 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */,
3735 sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */,
3736 sizeof(?) /* ProcessHandleCheckingMode */,
3737 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION) /* ProcessKeepAliveCount */,
3738 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION) /* ProcessRevokeFileHandles */,
3739 sizeof(PROCESS_WORKING_SET_CONTROL) /* ProcessWorkingSetControl */,
3740 sizeof(?) /* ProcessHandleTable */,
3741 sizeof(?) /* ProcessCheckStackExtentsMode */,
3742 sizeof(buf) /* ProcessCommandLineInformation */,
3743 sizeof(PS_PROTECTION) /* ProcessProtectionInformation */,
3744 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO) /* ProcessMemoryExhaustion */,
3745 sizeof(PROCESS_FAULT_INFORMATION) /* ProcessFaultInformation */,
3746 sizeof(PROCESS_TELEMETRY_ID_INFORMATION) /* ProcessTelemetryIdInformation */,
3747 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION) /* ProcessCommitReleaseInformation */,
3748 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3749 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3750 0 /* ProcessReserved1Information */,
3751 0 /* ProcessReserved2Information */,
3752 sizeof(?) /* ProcessSubsystemProcess */,
3753 sizeof(PROCESS_JOB_MEMORY_INFO) /* ProcessJobMemoryInformation */,
3754 #endif
3756 ULONG i, status, ret_len;
3757 BOOL is_current = hproc == GetCurrentProcess();
3759 if (!pNtQueryInformationProcess)
3761 win_skip("NtQueryInformationProcess is not available on this platform\n");
3762 return;
3765 for (i = 0; i < ARRAY_SIZE(info_size); i++)
3767 ret_len = 0;
3768 status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len);
3769 if (status == STATUS_NOT_IMPLEMENTED) continue;
3770 if (status == STATUS_INVALID_INFO_CLASS) continue;
3771 if (status == STATUS_INFO_LENGTH_MISMATCH) continue;
3773 switch (i)
3775 case ProcessBasicInformation:
3776 case ProcessQuotaLimits:
3777 case ProcessTimes:
3778 case ProcessPriorityClass:
3779 case ProcessPriorityBoost:
3780 case ProcessLUIDDeviceMapsEnabled:
3781 case ProcessIoPriority:
3782 case ProcessIoCounters:
3783 case ProcessVmCounters:
3784 case ProcessWow64Information:
3785 case ProcessDefaultHardErrorMode:
3786 case ProcessHandleCount:
3787 case ProcessImageFileName:
3788 case ProcessImageInformation:
3789 case ProcessCycleTime:
3790 case ProcessPagePriority:
3791 case ProcessImageFileNameWin32:
3792 ok(status == STATUS_SUCCESS, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len);
3793 break;
3795 case ProcessAffinityMask:
3796 case ProcessBreakOnTermination:
3797 ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */,
3798 "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i, status, ret_len);
3799 break;
3801 case ProcessDebugObjectHandle:
3802 ok(status == STATUS_ACCESS_DENIED || status == STATUS_PORT_NOT_SET,
3803 "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len);
3804 break;
3805 case ProcessCookie:
3806 if (is_current)
3807 ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER /* before win8 */,
3808 "for info %lu got %08lx (ret_len %lu)\n", i, status, ret_len);
3809 else
3810 ok(status == STATUS_INVALID_PARAMETER /* before win8 */ || status == STATUS_ACCESS_DENIED,
3811 "for info %lu got %08lx (ret_len %lu)\n", i, status, ret_len);
3812 break;
3813 case ProcessExecuteFlags:
3814 case ProcessDebugPort:
3815 case ProcessDebugFlags:
3816 if (is_current)
3817 ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER,
3818 "for info %lu, got %08lx (ret_len %lu)\n", i, status, ret_len);
3819 else
3820 todo_wine
3821 ok(status == STATUS_ACCESS_DENIED,
3822 "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len);
3823 break;
3825 default:
3826 if (is_current)
3827 ok(status == STATUS_SUCCESS || status == STATUS_UNSUCCESSFUL || status == STATUS_INVALID_PARAMETER,
3828 "for info %lu, got %08lx (ret_len %lu)\n", i, status, ret_len);
3829 else
3830 ok(status == STATUS_ACCESS_DENIED,
3831 "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i, status, ret_len);
3832 break;
3837 static void test_GetLogicalProcessorInformationEx(void)
3839 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info;
3840 DWORD len;
3841 BOOL ret;
3843 if (!pGetLogicalProcessorInformationEx)
3845 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3846 return;
3849 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, NULL);
3850 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %ld\n", ret, GetLastError());
3852 len = 0;
3853 ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len);
3854 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %ld\n", ret, GetLastError());
3855 ok(len > 0, "got %lu\n", len);
3857 len = 0;
3858 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len);
3859 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %ld\n", ret, GetLastError());
3860 ok(len > 0, "got %lu\n", len);
3862 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
3863 ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len);
3864 ok(ret, "got %d, error %ld\n", ret, GetLastError());
3865 ok(info->Size > 0, "got %lu\n", info->Size);
3866 HeapFree(GetProcessHeap(), 0, info);
3869 static void test_GetSystemCpuSetInformation(void)
3871 SYSTEM_CPU_SET_INFORMATION *info, *info_nt;
3872 HANDLE process = GetCurrentProcess();
3873 ULONG size, expected_size;
3874 NTSTATUS status;
3875 SYSTEM_INFO si;
3876 BOOL ret;
3878 if (!pGetSystemCpuSetInformation)
3880 win_skip("GetSystemCpuSetInformation() is not supported.\n");
3881 return;
3884 GetSystemInfo(&si);
3886 expected_size = sizeof(*info) * si.dwNumberOfProcessors;
3888 if (0)
3890 /* Crashes on Windows with NULL return length. */
3891 pGetSystemCpuSetInformation(NULL, 0, NULL, process, 0);
3894 size = 0xdeadbeef;
3895 SetLastError(0xdeadbeef);
3896 ret = pGetSystemCpuSetInformation(NULL, size, &size, process, 0);
3897 ok(!ret && GetLastError() == ERROR_NOACCESS, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
3898 ok(!size, "Got unexpected size %lu.\n", size);
3900 size = 0xdeadbeef;
3901 SetLastError(0xdeadbeef);
3902 ret = pGetSystemCpuSetInformation(NULL, 0, &size, (HANDLE)0xdeadbeef, 0);
3903 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
3904 ok(!size, "Got unexpected size %lu.\n", size);
3906 size = 0xdeadbeef;
3907 SetLastError(0xdeadbeef);
3908 ret = pGetSystemCpuSetInformation(NULL, 0, &size, process, 0);
3909 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
3910 ok(size == expected_size, "Got unexpected size %lu.\n", size);
3912 info = heap_alloc(size);
3913 info_nt = heap_alloc(size);
3915 status = pNtQuerySystemInformationEx(SystemCpuSetInformation, &process, sizeof(process), info_nt, expected_size, NULL);
3916 ok(!status, "Got unexpected status %#lx.\n", status);
3918 size = 0xdeadbeef;
3919 SetLastError(0xdeadbeef);
3920 ret = pGetSystemCpuSetInformation(info, expected_size, &size, process, 0);
3921 ok(ret && GetLastError() == 0xdeadbeef, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
3922 ok(size == expected_size, "Got unexpected size %lu.\n", size);
3924 ok(!memcmp(info, info_nt, expected_size), "Info does not match NtQuerySystemInformationEx().\n");
3926 heap_free(info_nt);
3927 heap_free(info);
3930 static void test_largepages(void)
3932 SIZE_T size;
3934 if (!pGetLargePageMinimum) {
3935 win_skip("No GetLargePageMinimum support.\n");
3936 return;
3938 size = pGetLargePageMinimum();
3940 ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %Id size\n", size);
3943 struct proc_thread_attr
3945 DWORD_PTR attr;
3946 SIZE_T size;
3947 void *value;
3950 struct _PROC_THREAD_ATTRIBUTE_LIST
3952 DWORD mask; /* bitmask of items in list */
3953 DWORD size; /* max number of items in list */
3954 DWORD count; /* number of items in list */
3955 DWORD pad;
3956 DWORD_PTR unk;
3957 struct proc_thread_attr attrs[10];
3960 static void test_ProcThreadAttributeList(void)
3962 BOOL ret;
3963 SIZE_T size, needed;
3964 int i;
3965 struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list;
3966 HANDLE handles[4];
3968 if (!pInitializeProcThreadAttributeList)
3970 win_skip("No support for ProcThreadAttributeList\n");
3971 return;
3974 for (i = 0; i <= 10; i++)
3976 needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[i]);
3977 ret = pInitializeProcThreadAttributeList(NULL, i, 0, &size);
3978 ok(!ret, "got %d\n", ret);
3979 if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */
3980 break;
3981 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %ld\n", GetLastError());
3982 ok(size == needed, "%d: got %Id expect %Id\n", i, size, needed);
3984 memset(&list, 0xcc, sizeof(list));
3985 ret = pInitializeProcThreadAttributeList(&list, i, 0, &size);
3986 ok(ret, "got %d\n", ret);
3987 ok(list.mask == 0, "%d: got %08lx\n", i, list.mask);
3988 ok(list.size == i, "%d: got %08lx\n", i, list.size);
3989 ok(list.count == 0, "%d: got %08lx\n", i, list.count);
3990 ok(list.unk == 0, "%d: got %08Ix\n", i, list.unk);
3993 memset(handles, 0, sizeof(handles));
3994 memset(&expect_list, 0xcc, sizeof(expect_list));
3995 expect_list.mask = 0;
3996 expect_list.size = i - 1;
3997 expect_list.count = 0;
3998 expect_list.unk = 0;
4000 ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
4001 ok(!ret, "got %d\n", ret);
4002 ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %ld\n", GetLastError());
4004 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL);
4005 ok(!ret, "got %d\n", ret);
4006 ok(GetLastError() == ERROR_BAD_LENGTH, "got %ld\n", GetLastError());
4008 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL);
4009 ok(!ret, "got %d\n", ret);
4010 ok(GetLastError() == ERROR_BAD_LENGTH, "got %ld\n", GetLastError());
4012 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
4013 ok(ret, "got %d\n", ret);
4015 expect_list.mask |= 1 << ProcThreadAttributeParentProcess;
4016 expect_list.attrs[0].attr = PROC_THREAD_ATTRIBUTE_PARENT_PROCESS;
4017 expect_list.attrs[0].size = sizeof(handles[0]);
4018 expect_list.attrs[0].value = handles;
4019 expect_list.count++;
4021 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
4022 ok(!ret, "got %d\n", ret);
4023 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %ld\n", GetLastError());
4025 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL);
4026 ok(!ret, "got %d\n", ret);
4027 ok(GetLastError() == ERROR_BAD_LENGTH, "got %ld\n", GetLastError());
4029 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
4030 ok(ret, "got %d\n", ret);
4032 expect_list.mask |= 1 << ProcThreadAttributeHandleList;
4033 expect_list.attrs[1].attr = PROC_THREAD_ATTRIBUTE_HANDLE_LIST;
4034 expect_list.attrs[1].size = sizeof(handles);
4035 expect_list.attrs[1].value = handles;
4036 expect_list.count++;
4038 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
4039 ok(!ret, "got %d\n", ret);
4040 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %ld\n", GetLastError());
4042 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
4043 ok(ret || GetLastError() == ERROR_NOT_SUPPORTED, "got %d gle %ld\n", ret, GetLastError());
4045 if (ret)
4047 expect_list.mask |= 1 << ProcThreadAttributeIdealProcessor;
4048 expect_list.attrs[2].attr = PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR;
4049 expect_list.attrs[2].size = sizeof(PROCESSOR_NUMBER);
4050 expect_list.attrs[2].value = handles;
4051 expect_list.count++;
4054 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, handles, sizeof(handles[0]), NULL, NULL);
4055 ok(ret || broken(GetLastError() == ERROR_NOT_SUPPORTED), "got %d gle %ld\n", ret, GetLastError());
4057 if (ret)
4059 unsigned int i = expect_list.count++;
4060 expect_list.mask |= 1 << ProcThreadAttributePseudoConsole;
4061 expect_list.attrs[i].attr = PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE;
4062 expect_list.attrs[i].size = sizeof(HPCON);
4063 expect_list.attrs[i].value = handles;
4066 ok(!memcmp(&list, &expect_list, size), "mismatch\n");
4068 pDeleteProcThreadAttributeList(&list);
4071 /* level 0: Main test process
4072 * level 1: Process created by level 0 process without handle inheritance
4073 * level 2: Process created by level 1 process with handle inheritance and level 0
4074 * process parent substitute.
4075 * level 255: Process created by level 1 process during invalid parent handles testing. */
4076 static void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
4078 PROCESS_BASIC_INFORMATION pbi;
4079 char buffer[MAX_PATH + 64];
4080 HANDLE write_pipe = NULL;
4081 PROCESS_INFORMATION info;
4082 SECURITY_ATTRIBUTES sa;
4083 STARTUPINFOEXA si;
4084 DWORD parent_id;
4085 NTSTATUS status;
4086 ULONG pbi_size;
4087 HANDLE parent;
4088 DWORD size;
4089 BOOL ret;
4091 struct
4093 HANDLE parent;
4094 DWORD parent_id;
4096 parent_data;
4098 if (level == 255)
4099 return;
4101 if (!pInitializeProcThreadAttributeList)
4103 win_skip("No support for ProcThreadAttributeList.\n");
4104 return;
4107 memset(&sa, 0, sizeof(sa));
4108 sa.nLength = sizeof(sa);
4109 sa.bInheritHandle = TRUE;
4111 if (!level)
4113 ret = CreatePipe(&read_pipe, &write_pipe, &sa, 0);
4114 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4116 parent_data.parent = OpenProcess(PROCESS_CREATE_PROCESS | PROCESS_QUERY_INFORMATION, TRUE, GetCurrentProcessId());
4117 parent_data.parent_id = GetCurrentProcessId();
4119 else
4121 status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &pbi_size);
4122 ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
4123 parent_id = pbi.InheritedFromUniqueProcessId;
4125 memset(&parent_data, 0, sizeof(parent_data));
4126 ret = ReadFile(read_pipe, &parent_data, sizeof(parent_data), &size, NULL);
4127 ok((level == 2 && ret) || (level == 1 && !ret && GetLastError() == ERROR_INVALID_HANDLE),
4128 "Got unexpected ret %#x, level %u, GetLastError() %lu.\n",
4129 ret, level, GetLastError());
4132 if (level == 2)
4134 ok(parent_id == parent_data.parent_id, "Got parent id %lu, parent_data.parent_id %lu.\n",
4135 parent_id, parent_data.parent_id);
4136 return;
4139 memset(&si, 0, sizeof(si));
4140 si.StartupInfo.cb = sizeof(si);
4142 if (level)
4144 HANDLE handle;
4145 SIZE_T size;
4147 ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size);
4148 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
4149 "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4151 sprintf(buffer, "\"%s\" process parent %u %p", selfname, 255, read_pipe);
4153 #if 0
4154 /* Crashes on some Windows installations, otherwise successfully creates process. */
4155 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT,
4156 NULL, NULL, (STARTUPINFOA *)&si, &info);
4157 ok(ret, "Got unexpected ret %#x, GetLastError() %u.\n", ret, GetLastError());
4158 wait_and_close_child_process(&info);
4159 #endif
4160 si.lpAttributeList = heap_alloc(size);
4161 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4162 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4163 handle = OpenProcess(PROCESS_CREATE_PROCESS, TRUE, GetCurrentProcessId());
4164 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4165 &handle, sizeof(handle), NULL, NULL);
4166 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4167 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
4168 NULL, NULL, (STARTUPINFOA *)&si, &info);
4169 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4170 wait_and_close_child_process(&info);
4171 CloseHandle(handle);
4172 pDeleteProcThreadAttributeList(si.lpAttributeList);
4173 heap_free(si.lpAttributeList);
4175 si.lpAttributeList = heap_alloc(size);
4176 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4177 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4178 handle = (HANDLE)0xdeadbeef;
4179 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4180 &handle, sizeof(handle), NULL, NULL);
4181 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4182 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
4183 NULL, NULL, (STARTUPINFOA *)&si, &info);
4184 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n",
4185 ret, GetLastError());
4186 pDeleteProcThreadAttributeList(si.lpAttributeList);
4187 heap_free(si.lpAttributeList);
4189 si.lpAttributeList = heap_alloc(size);
4190 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4191 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4192 handle = NULL;
4193 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4194 &handle, sizeof(handle), NULL, NULL);
4195 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4196 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
4197 NULL, NULL, (STARTUPINFOA *)&si, &info);
4198 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n",
4199 ret, GetLastError());
4200 pDeleteProcThreadAttributeList(si.lpAttributeList);
4201 heap_free(si.lpAttributeList);
4203 si.lpAttributeList = heap_alloc(size);
4204 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4205 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4206 handle = GetCurrentProcess();
4207 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4208 &handle, sizeof(handle), NULL, NULL);
4209 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4210 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT,
4211 NULL, NULL, (STARTUPINFOA *)&si, &info);
4212 /* Broken on Vista / w7 / w10. */
4213 ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_HANDLE),
4214 "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4215 if (ret)
4216 wait_and_close_child_process(&info);
4217 pDeleteProcThreadAttributeList(si.lpAttributeList);
4218 heap_free(si.lpAttributeList);
4220 si.lpAttributeList = heap_alloc(size);
4221 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4222 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4224 parent = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, parent_id);
4226 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
4227 &parent, sizeof(parent), NULL, NULL);
4228 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4231 sprintf(buffer, "\"%s\" process parent %u %p", selfname, level + 1, read_pipe);
4232 ret = CreateProcessA(NULL, buffer, NULL, NULL, level == 1, level == 1 ? EXTENDED_STARTUPINFO_PRESENT : 0,
4233 NULL, NULL, (STARTUPINFOA *)&si, &info);
4234 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4236 if (level)
4238 pDeleteProcThreadAttributeList(si.lpAttributeList);
4239 heap_free(si.lpAttributeList);
4240 CloseHandle(parent);
4242 else
4244 ret = WriteFile(write_pipe, &parent_data, sizeof(parent_data), &size, NULL);
4247 wait_and_close_child_process(&info);
4249 if (!level)
4251 CloseHandle(read_pipe);
4252 CloseHandle(write_pipe);
4253 CloseHandle(parent_data.parent);
4257 static void test_handle_list_attribute(BOOL child, HANDLE handle1, HANDLE handle2)
4259 char buffer[MAX_PATH + 64];
4260 HANDLE pipe[2];
4261 PROCESS_INFORMATION info;
4262 STARTUPINFOEXA si;
4263 SIZE_T size;
4264 BOOL ret;
4265 SECURITY_ATTRIBUTES sa;
4267 if (child)
4269 char name1[256], name2[256];
4270 DWORD flags;
4272 flags = 0;
4273 ret = GetHandleInformation(handle1, &flags);
4274 ok(ret, "Failed to get handle info, error %ld.\n", GetLastError());
4275 ok(flags == HANDLE_FLAG_INHERIT, "Unexpected flags %#lx.\n", flags);
4276 ret = GetFileInformationByHandleEx(handle1, FileNameInfo, name1, sizeof(name1));
4277 ok(ret, "Failed to get pipe name, error %ld\n", GetLastError());
4278 CloseHandle(handle1);
4279 flags = 0;
4280 ret = GetHandleInformation(handle2, &flags);
4281 if (ret)
4283 ok(!(flags & HANDLE_FLAG_INHERIT), "Parent's handle shouldn't have been inherited\n");
4284 ret = GetFileInformationByHandleEx(handle2, FileNameInfo, name2, sizeof(name2));
4285 ok(!ret || strcmp(name1, name2), "Parent's handle shouldn't have been inherited\n");
4287 else
4288 ok(GetLastError() == ERROR_INVALID_HANDLE, "Unexpected return value, error %ld.\n", GetLastError());
4290 return;
4293 ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size);
4294 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
4295 "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4297 memset(&si, 0, sizeof(si));
4298 si.StartupInfo.cb = sizeof(si);
4299 si.lpAttributeList = heap_alloc(size);
4300 ret = pInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
4301 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4303 memset(&sa, 0, sizeof(sa));
4304 sa.nLength = sizeof(sa);
4305 sa.bInheritHandle = TRUE;
4307 ret = CreatePipe(&pipe[0], &pipe[1], &sa, 1024);
4308 ok(ret, "Failed to create a pipe.\n");
4310 ret = pUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &pipe[0],
4311 sizeof(pipe[0]), NULL, NULL);
4312 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4314 sprintf(buffer, "\"%s\" process handlelist %p %p", selfname, pipe[0], pipe[1]);
4315 ret = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
4316 (STARTUPINFOA *)&si, &info);
4317 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4319 wait_and_close_child_process(&info);
4321 CloseHandle(pipe[0]);
4322 CloseHandle(pipe[1]);
4325 static void test_dead_process(void)
4327 DWORD_PTR data[256];
4328 PROCESS_BASIC_INFORMATION basic;
4329 SYSTEM_PROCESS_INFORMATION *spi;
4330 SECTION_IMAGE_INFORMATION image;
4331 PROCESS_INFORMATION pi;
4332 PROCESS_PRIORITY_CLASS *prio = (PROCESS_PRIORITY_CLASS *)data;
4333 BYTE *buffer = NULL;
4334 BOOL found;
4335 ULONG size = 0;
4336 DWORD offset = 0;
4337 NTSTATUS status;
4339 create_process("exit", &pi);
4340 wait_child_process(pi.hProcess);
4341 Sleep(100);
4343 memset( data, 0, sizeof(data) );
4344 status = NtQueryInformationProcess( pi.hProcess, ProcessImageFileName, data, sizeof(data), NULL);
4345 ok( !status, "ProcessImageFileName failed %lx\n", status );
4346 ok( ((UNICODE_STRING *)data)->Length, "ProcessImageFileName not set\n" );
4347 ok( ((UNICODE_STRING *)data)->Buffer[0] == '\\', "ProcessImageFileName not set\n" );
4349 memset( prio, 0xcc, sizeof(*prio) );
4350 status = NtQueryInformationProcess( pi.hProcess, ProcessPriorityClass, prio, sizeof(*prio), NULL);
4351 ok( !status, "ProcessPriorityClass failed %lx\n", status );
4352 ok( prio->PriorityClass != 0xcc, "ProcessPriorityClass not set\n" );
4354 memset( &basic, 0xcc, sizeof(basic) );
4355 status = NtQueryInformationProcess( pi.hProcess, ProcessBasicInformation, &basic, sizeof(basic), NULL);
4356 ok( !status, "ProcessBasicInformation failed %lx\n", status );
4357 ok( basic.ExitStatus == 0, "ProcessBasicInformation info modified\n" );
4359 memset( &image, 0xcc, sizeof(image) );
4360 status = NtQueryInformationProcess( pi.hProcess, ProcessImageInformation, &image, sizeof(image), NULL);
4361 ok( status == STATUS_PROCESS_IS_TERMINATING, "ProcessImageInformation wrong error %lx\n", status );
4362 ok( image.Machine == 0xcccc, "ProcessImageInformation info modified\n" );
4364 while ((status = NtQuerySystemInformation(SystemProcessInformation, buffer, size, &size)) == STATUS_INFO_LENGTH_MISMATCH)
4366 free(buffer);
4367 buffer = malloc(size);
4369 ok(status == STATUS_SUCCESS, "got %#lx\n", status);
4370 found = FALSE;
4373 spi = (SYSTEM_PROCESS_INFORMATION *)(buffer + offset);
4374 if (spi->UniqueProcessId == ULongToHandle(pi.dwProcessId))
4376 found = TRUE;
4377 break;
4379 offset += spi->NextEntryOffset;
4380 } while (spi->NextEntryOffset);
4381 ok( !found, "process still enumerated\n" );
4382 CloseHandle(pi.hProcess);
4383 CloseHandle(pi.hThread);
4386 static void test_nested_jobs_child(unsigned int index)
4388 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
4389 HANDLE job, job_parent, job_other, port;
4390 PROCESS_INFORMATION pi;
4391 OVERLAPPED *overlapped;
4392 char job_name[32];
4393 ULONG_PTR value;
4394 DWORD dead_pid;
4395 BOOL ret, out;
4396 DWORD key;
4398 sprintf(job_name, "test_nested_jobs_%u", index);
4399 job = pOpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_SET_ATTRIBUTES | JOB_OBJECT_QUERY
4400 | JOB_OBJECT_TERMINATE, FALSE, job_name);
4401 ok(!!job, "OpenJobObjectA error %lu\n", GetLastError());
4403 sprintf(job_name, "test_nested_jobs_%u", !index);
4404 job_other = pOpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_SET_ATTRIBUTES | JOB_OBJECT_QUERY
4405 | JOB_OBJECT_TERMINATE, FALSE, job_name);
4406 ok(!!job_other, "OpenJobObjectA error %lu\n", GetLastError());
4408 job_parent = pCreateJobObjectW(NULL, NULL);
4409 ok(!!job_parent, "CreateJobObjectA error %lu\n", GetLastError());
4411 ret = pAssignProcessToJobObject(job_parent, GetCurrentProcess());
4412 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
4414 create_process("wait", &pi);
4416 ret = pAssignProcessToJobObject(job_parent, pi.hProcess);
4417 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED) /* Supported since Windows 8. */,
4418 "AssignProcessToJobObject error %lu\n", GetLastError());
4419 if (!ret)
4421 win_skip("Nested jobs are not supported.\n");
4422 goto done;
4424 ret = pAssignProcessToJobObject(job, pi.hProcess);
4425 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
4427 out = FALSE;
4428 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
4429 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4430 ok(out, "IsProcessInJob returned out=%u\n", out);
4432 out = FALSE;
4433 ret = pIsProcessInJob(pi.hProcess, job, &out);
4434 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4435 ok(out, "IsProcessInJob returned out=%u\n", out);
4437 out = TRUE;
4438 ret = pIsProcessInJob(GetCurrentProcess(), job, &out);
4439 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4440 ok(!out, "IsProcessInJob returned out=%u\n", out);
4442 out = FALSE;
4443 ret = pIsProcessInJob(pi.hProcess, job, &out);
4444 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4445 ok(out, "IsProcessInJob returned out=%u\n", out);
4447 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
4448 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
4450 TerminateProcess(pi.hProcess, 0);
4451 wait_child_process(pi.hProcess);
4452 CloseHandle(pi.hProcess);
4453 CloseHandle(pi.hThread);
4455 dead_pid = pi.dwProcessId;
4457 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
4458 ok(!!port, "CreateIoCompletionPort error %lu\n", GetLastError());
4460 port_info.CompletionPort = port;
4461 port_info.CompletionKey = job;
4462 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
4463 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
4464 port_info.CompletionKey = job_parent;
4465 ret = pSetInformationJobObject(job_parent, JobObjectAssociateCompletionPortInformation,
4466 &port_info, sizeof(port_info));
4467 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
4469 create_process("wait", &pi);
4470 out = FALSE;
4471 ret = pIsProcessInJob(pi.hProcess, job, &out);
4472 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4473 ok(out, "IsProcessInJob returned out=%u\n", out);
4475 out = FALSE;
4476 ret = pIsProcessInJob(pi.hProcess, job_parent, &out);
4477 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4478 ok(out, "IsProcessInJob returned out=%u\n", out);
4480 /* The first already dead child process still shows up randomly. */
4483 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
4484 } while (ret && (ULONG_PTR)overlapped == dead_pid);
4486 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4487 ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %lx\n", key);
4488 ok((HANDLE)value == job, "unexpected value %p\n", (void *)value);
4489 ok((ULONG_PTR)overlapped == GetCurrentProcessId(), "unexpected pid %#lx\n", (DWORD)(DWORD_PTR)overlapped);
4493 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
4494 } while (ret && (ULONG_PTR)overlapped == dead_pid);
4496 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4497 ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %lx\n", key);
4498 ok((HANDLE)value == job_parent, "unexpected value %p\n", (void *)value);
4499 ok((ULONG_PTR)overlapped == GetCurrentProcessId(), "unexpected pid %#lx\n", (DWORD)(DWORD_PTR)overlapped);
4501 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
4502 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job_parent, pi.dwProcessId, 0);
4504 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
4505 ok(!ret, "GetQueuedCompletionStatus succeeded.\n");
4507 if (index)
4509 ret = pAssignProcessToJobObject(job_other, GetCurrentProcess());
4510 ok(!ret, "AssignProcessToJobObject succeeded\n");
4511 ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %lu.\n", GetLastError());
4514 CloseHandle(port);
4516 done:
4517 TerminateProcess(pi.hProcess, 0);
4518 wait_child_process(pi.hProcess);
4520 CloseHandle(pi.hProcess);
4521 CloseHandle(pi.hThread);
4522 CloseHandle(job_parent);
4523 CloseHandle(job);
4524 CloseHandle(job_other);
4527 static void test_nested_jobs(void)
4529 BOOL ret, already_in_job = TRUE, create_succeeded = FALSE;
4530 PROCESS_INFORMATION info[2];
4531 char buffer[MAX_PATH + 26];
4532 STARTUPINFOA si = {0};
4533 HANDLE job1, job2;
4534 unsigned int i;
4536 if (!pIsProcessInJob)
4538 win_skip("IsProcessInJob not available.\n");
4539 return;
4542 job1 = pCreateJobObjectW(NULL, NULL);
4543 ok(!!job1, "CreateJobObjectW failed, error %lu.\n", GetLastError());
4544 job2 = pCreateJobObjectW(NULL, NULL);
4545 ok(!!job2, "CreateJobObjectW failed, error %lu.\n", GetLastError());
4547 create_succeeded = TRUE;
4548 sprintf(buffer, "\"%s\" process wait", selfname);
4549 for (i = 0; i < 2; ++i)
4551 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &info[i]);
4552 if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
4554 create_succeeded = FALSE;
4555 break;
4557 ok(ret, "CreateProcessA error %lu\n", GetLastError());
4560 if (create_succeeded)
4562 ret = pIsProcessInJob(info[0].hProcess, NULL, &already_in_job);
4563 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4565 if (!already_in_job)
4567 ret = pAssignProcessToJobObject(job2, info[1].hProcess);
4568 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
4570 ret = pAssignProcessToJobObject(job1, info[0].hProcess);
4571 ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError());
4573 ret = pAssignProcessToJobObject(job2, info[0].hProcess);
4574 ok(!ret, "AssignProcessToJobObject succeeded\n");
4575 ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %lu.\n", GetLastError());
4577 TerminateProcess(info[1].hProcess, 0);
4578 wait_child_process(info[1].hProcess);
4579 CloseHandle(info[1].hProcess);
4580 CloseHandle(info[1].hThread);
4582 ret = pAssignProcessToJobObject(job2, info[0].hProcess);
4583 ok(!ret, "AssignProcessToJobObject succeeded\n");
4584 ok(GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected error %lu.\n", GetLastError());
4587 TerminateProcess(info[0].hProcess, 0);
4588 wait_child_process(info[0].hProcess);
4589 CloseHandle(info[0].hProcess);
4590 CloseHandle(info[0].hThread);
4593 if (already_in_job)
4595 win_skip("Test process is already in job, can't test parenting non-empty job.\n");
4598 CloseHandle(job1);
4599 CloseHandle(job2);
4601 job1 = pCreateJobObjectW(NULL, L"test_nested_jobs_0");
4602 ok(!!job1, "CreateJobObjectW failed, error %lu.\n", GetLastError());
4603 job2 = pCreateJobObjectW(NULL, L"test_nested_jobs_1");
4604 ok(!!job2, "CreateJobObjectW failed, error %lu.\n", GetLastError());
4606 sprintf(buffer, "\"%s\" process nested_jobs 0", selfname);
4607 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info[0]),
4608 "CreateProcess failed\n");
4609 wait_child_process(info[0].hProcess);
4610 sprintf(buffer, "\"%s\" process nested_jobs 1", selfname);
4611 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info[1]),
4612 "CreateProcess failed\n");
4613 wait_child_process(info[1].hProcess);
4614 for (i = 0; i < 2; ++i)
4616 CloseHandle(info[i].hProcess);
4617 CloseHandle(info[i].hThread);
4620 CloseHandle(job1);
4621 CloseHandle(job2);
4624 static void test_job_list_attribute(HANDLE parent_job)
4626 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION job_info;
4627 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
4628 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
4629 PPROC_THREAD_ATTRIBUTE_LIST attrs;
4630 char buffer[MAX_PATH + 19];
4631 PROCESS_INFORMATION pi;
4632 OVERLAPPED *overlapped;
4633 HANDLE jobs[2], port;
4634 STARTUPINFOEXA si;
4635 ULONG_PTR value;
4636 BOOL ret, out;
4637 HANDLE tmp;
4638 SIZE_T size;
4639 DWORD key;
4641 if (!pInitializeProcThreadAttributeList)
4643 win_skip("No support for ProcThreadAttributeList\n");
4644 return;
4647 ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size);
4648 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
4649 "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4650 attrs = heap_alloc(size);
4653 jobs[0] = (HANDLE)0xdeadbeef;
4654 jobs[1] = NULL;
4656 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4657 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4658 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
4659 sizeof(*jobs), NULL, NULL);
4660 if (!ret && GetLastError() == ERROR_NOT_SUPPORTED)
4662 /* Supported since Win10. */
4663 win_skip("PROC_THREAD_ATTRIBUTE_JOB_LIST is not supported.\n");
4664 pDeleteProcThreadAttributeList(attrs);
4665 heap_free(attrs);
4666 return;
4668 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4670 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4671 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4672 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
4673 3, NULL, NULL);
4674 ok(!ret && GetLastError() == ERROR_BAD_LENGTH, "Got unexpected ret %#x, GetLastError() %lu.\n",
4675 ret, GetLastError());
4677 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4678 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4679 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
4680 sizeof(*jobs) * 2, NULL, NULL);
4681 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4683 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4684 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4685 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
4686 sizeof(*jobs), NULL, NULL);
4688 memset(&si, 0, sizeof(si));
4689 si.StartupInfo.cb = sizeof(si);
4690 si.lpAttributeList = attrs;
4691 sprintf(buffer, "\"%s\" process wait", selfname);
4693 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
4694 (STARTUPINFOA *)&si, &pi);
4695 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n",
4696 ret, GetLastError());
4698 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4699 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4700 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1,
4701 sizeof(*jobs), NULL, NULL);
4702 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
4703 (STARTUPINFOA *)&si, &pi);
4704 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected ret %#x, GetLastError() %lu.\n",
4705 ret, GetLastError());
4707 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4708 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4709 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, &parent_job,
4710 sizeof(parent_job), NULL, NULL);
4711 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
4712 (STARTUPINFOA *)&si, &pi);
4713 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4715 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
4716 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4717 ok(out, "IsProcessInJob returned out=%u\n", out);
4719 TerminateProcess(pi.hProcess, 0);
4720 wait_and_close_child_process(&pi);
4722 jobs[0] = pCreateJobObjectW(NULL, NULL);
4723 ok(!!jobs[0], "CreateJobObjectA error %lu\n", GetLastError());
4724 jobs[1] = pCreateJobObjectW(NULL, NULL);
4725 ok(!!jobs[1], "CreateJobObjectA error %lu\n", GetLastError());
4727 /* Breakaway works for the inherited job only. */
4728 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
4729 ret = pSetInformationJobObject(parent_job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
4730 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
4731 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK
4732 | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
4733 ret = pSetInformationJobObject(jobs[1], JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
4734 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
4736 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4737 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4738 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1,
4739 sizeof(*jobs), NULL, NULL);
4740 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT
4741 | CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, (STARTUPINFOA *)&si, &pi);
4742 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4744 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
4745 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4746 ok(!out, "IsProcessInJob returned out=%u\n", out);
4748 ret = pIsProcessInJob(pi.hProcess, jobs[1], &out);
4749 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4750 ok(out, "IsProcessInJob returned out=%u\n", out);
4752 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
4753 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4754 ok(!out, "IsProcessInJob returned out=%u\n", out);
4756 TerminateProcess(pi.hProcess, 0);
4757 wait_and_close_child_process(&pi);
4759 CloseHandle(jobs[1]);
4760 jobs[1] = pCreateJobObjectW(NULL, NULL);
4761 ok(!!jobs[1], "CreateJobObjectA error %lu\n", GetLastError());
4763 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4764 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4765 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1,
4766 sizeof(*jobs), NULL, NULL);
4767 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT,
4768 NULL, NULL, (STARTUPINFOA *)&si, &pi);
4769 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4771 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
4772 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4773 ok(out, "IsProcessInJob returned out=%u\n", out);
4775 ret = pIsProcessInJob(pi.hProcess, jobs[1], &out);
4776 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4777 ok(out, "IsProcessInJob returned out=%u\n", out);
4779 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
4780 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4781 ok(!out, "IsProcessInJob returned out=%u\n", out);
4783 TerminateProcess(pi.hProcess, 0);
4784 wait_and_close_child_process(&pi);
4786 ret = pQueryInformationJobObject(jobs[0], JobObjectBasicAccountingInformation, &job_info,
4787 sizeof(job_info), NULL);
4788 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
4789 ok(!job_info.TotalProcesses, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses);
4790 ok(!job_info.ActiveProcesses, "Got unexpected ActiveProcesses %lu.\n", job_info.ActiveProcesses);
4792 ret = pQueryInformationJobObject(jobs[1], JobObjectBasicAccountingInformation, &job_info,
4793 sizeof(job_info), NULL);
4794 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
4795 ok(job_info.TotalProcesses == 1, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses);
4796 ok(!job_info.ActiveProcesses || job_info.ActiveProcesses == 1, "Got unexpected ActiveProcesses %lu.\n",
4797 job_info.ActiveProcesses);
4799 /* Fails due to the second job already has the parent other than the first job in the list. */
4800 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4801 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4802 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
4803 2 * sizeof(*jobs), NULL, NULL);
4805 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
4806 ok(!!port, "CreateIoCompletionPort error %lu\n", GetLastError());
4808 port_info.CompletionPort = port;
4809 port_info.CompletionKey = jobs[0];
4810 ret = pSetInformationJobObject(jobs[0], JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
4811 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
4813 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
4814 ok(!ret, "GetQueuedCompletionStatus succeeded.\n");
4816 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
4817 (STARTUPINFOA *)&si, &pi);
4818 ok(!ret && GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected ret %#x, GetLastError() %lu.\n",
4819 ret, GetLastError());
4821 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 100);
4822 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4823 ok(key == JOB_OBJECT_MSG_NEW_PROCESS, "unexpected key %lx\n", key);
4824 ok((HANDLE)value == jobs[0], "unexpected value %p\n", (void *)value);
4825 ok(!!overlapped, "Got zero pid.\n");
4827 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 100);
4828 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4829 ok(key == JOB_OBJECT_MSG_EXIT_PROCESS, "unexpected key %lx\n", key);
4830 ok((HANDLE)value == jobs[0], "unexpected value %p\n", (void *)value);
4831 ok(!!overlapped, "Got zero pid.\n");
4833 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 100);
4834 ok(ret, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4835 ok(key == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, "unexpected key %lx\n", key);
4836 ok((HANDLE)value == jobs[0], "unexpected value %p\n", (void *)value);
4837 ok(!overlapped, "Got unexpected overlapped %p.\n", overlapped);
4839 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, 0);
4840 ok(!ret, "GetQueuedCompletionStatus succeeded.\n");
4842 CloseHandle(port);
4844 /* The first job got updated even though the process creation failed. */
4845 ret = pQueryInformationJobObject(jobs[0], JobObjectBasicAccountingInformation, &job_info,
4846 sizeof(job_info), NULL);
4847 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
4848 ok(job_info.TotalProcesses == 1, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses);
4849 ok(!job_info.ActiveProcesses, "Got unexpected ActiveProcesses %lu.\n", job_info.ActiveProcesses);
4851 ret = pQueryInformationJobObject(jobs[1], JobObjectBasicAccountingInformation, &job_info,
4852 sizeof(job_info), NULL);
4853 ok(ret, "QueryInformationJobObject error %lu\n", GetLastError());
4854 ok(job_info.TotalProcesses == 1, "Got unexpected TotalProcesses %lu.\n", job_info.TotalProcesses);
4855 ok(!job_info.ActiveProcesses, "Got unexpected ActiveProcesses %lu.\n", job_info.ActiveProcesses);
4857 /* Check that the first job actually got the job_parent as parent. */
4858 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4859 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4860 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
4861 sizeof(*jobs), NULL, NULL);
4862 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT
4863 | CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, (STARTUPINFOA *)&si, &pi);
4864 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4866 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
4867 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4868 ok(out, "IsProcessInJob returned out=%u\n", out);
4870 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
4871 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4872 ok(out, "IsProcessInJob returned out=%u\n", out);
4874 TerminateProcess(pi.hProcess, 0);
4875 wait_and_close_child_process(&pi);
4877 tmp = jobs[0];
4878 jobs[0] = jobs[1];
4879 jobs[1] = tmp;
4881 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4882 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4883 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
4884 2 * sizeof(*jobs), NULL, NULL);
4885 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
4886 (STARTUPINFOA *)&si, &pi);
4887 ok(!ret && GetLastError() == ERROR_ACCESS_DENIED, "Got unexpected ret %#x, GetLastError() %lu.\n",
4888 ret, GetLastError());
4890 CloseHandle(jobs[0]);
4891 CloseHandle(jobs[1]);
4893 jobs[0] = pCreateJobObjectW(NULL, NULL);
4894 ok(!!jobs[0], "CreateJobObjectA error %lu\n", GetLastError());
4895 jobs[1] = pCreateJobObjectW(NULL, NULL);
4896 ok(!!jobs[1], "CreateJobObjectA error %lu\n", GetLastError());
4898 /* Create the job chain successfully and check the job chain. */
4899 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4900 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4901 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs,
4902 2 * sizeof(*jobs), NULL, NULL);
4903 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT,
4904 NULL, NULL, (STARTUPINFOA *)&si, &pi);
4905 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4907 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
4908 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4909 ok(out, "IsProcessInJob returned out=%u\n", out);
4911 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
4912 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4913 ok(out, "IsProcessInJob returned out=%u\n", out);
4915 ret = pIsProcessInJob(pi.hProcess, jobs[1], &out);
4916 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4917 ok(out, "IsProcessInJob returned out=%u\n", out);
4919 TerminateProcess(pi.hProcess, 0);
4920 wait_and_close_child_process(&pi);
4922 ret = pInitializeProcThreadAttributeList(attrs, 1, 0, &size);
4923 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4924 ret = pUpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST, jobs + 1,
4925 sizeof(*jobs), NULL, NULL);
4926 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT
4927 | CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, (STARTUPINFOA *)&si, &pi);
4928 ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError());
4930 ret = pIsProcessInJob(pi.hProcess, parent_job, &out);
4931 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4932 ok(out, "IsProcessInJob returned out=%u\n", out);
4934 ret = pIsProcessInJob(pi.hProcess, jobs[0], &out);
4935 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4936 ok(out, "IsProcessInJob returned out=%u\n", out);
4938 ret = pIsProcessInJob(pi.hProcess, jobs[1], &out);
4939 ok(ret, "IsProcessInJob error %lu\n", GetLastError());
4940 ok(out, "IsProcessInJob returned out=%u\n", out);
4942 TerminateProcess(pi.hProcess, 0);
4943 wait_and_close_child_process(&pi);
4945 CloseHandle(jobs[0]);
4946 CloseHandle(jobs[1]);
4948 pDeleteProcThreadAttributeList(attrs);
4949 heap_free(attrs);
4951 limit_info.BasicLimitInformation.LimitFlags = 0;
4952 ret = pSetInformationJobObject(parent_job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
4953 ok(ret, "SetInformationJobObject error %lu\n", GetLastError());
4956 static void test_services_exe(void)
4958 NTSTATUS status;
4959 ULONG size, offset, try;
4960 char *buf;
4961 SYSTEM_PROCESS_INFORMATION *spi;
4962 ULONG services_pid = 0, services_session_id = ~0;
4964 /* Check that passing a zero size returns a size suitable for the next call,
4965 * taking into account that in rare cases processes may start between the
4966 * two NtQuerySystemInformation() calls. So this may require a few tries.
4968 for (try = 0; try < 3; try++)
4970 status = NtQuerySystemInformation(SystemProcessInformation, NULL, 0, &size);
4971 ok(status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx\n", status);
4973 buf = malloc(size);
4974 status = NtQuerySystemInformation(SystemProcessInformation, buf, size, &size);
4975 if (status != STATUS_INFO_LENGTH_MISMATCH) break;
4976 free(buf);
4978 ok(status == STATUS_SUCCESS, "got %#lx\n", status);
4980 spi = (SYSTEM_PROCESS_INFORMATION *)buf;
4981 offset = 0;
4985 spi = (SYSTEM_PROCESS_INFORMATION *)(buf + offset);
4986 if (!wcsnicmp(spi->ProcessName.Buffer, L"services.exe", spi->ProcessName.Length/sizeof(WCHAR)))
4988 services_pid = HandleToUlong(spi->UniqueProcessId);
4989 services_session_id = spi->SessionId;
4991 offset += spi->NextEntryOffset;
4992 } while (spi->NextEntryOffset != 0);
4994 ok(services_pid != 0, "services.exe not found\n");
4995 todo_wine
4996 ok(services_session_id == 0, "got services.exe SessionId %lu\n", services_session_id);
4999 START_TEST(process)
5001 HANDLE job, hproc, h, h2;
5002 BOOL b = init();
5003 ok(b, "Basic init of CreateProcess test\n");
5004 if (!b) return;
5006 if (myARGC >= 3)
5008 if (!strcmp(myARGV[2], "dump") && myARGC >= 4)
5010 doChild(myARGV[3], (myARGC >= 5) ? myARGV[4] : NULL);
5011 return;
5013 else if (!strcmp(myARGV[2], "wait"))
5015 Sleep(30000);
5016 ok(0, "Child process not killed\n");
5017 return;
5019 else if (!strcmp(myARGV[2], "sync") && myARGC >= 4)
5021 HANDLE sem = OpenSemaphoreA(SYNCHRONIZE, FALSE, myARGV[3]);
5022 ok(sem != 0, "OpenSemaphoreA(%s) failed le=%lu\n", myARGV[3], GetLastError());
5023 if (sem)
5025 DWORD ret = WaitForSingleObject(sem, 30000);
5026 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject(%s) returned %lu\n", myARGV[3], ret);
5027 CloseHandle(sem);
5029 return;
5031 else if (!strcmp(myARGV[2], "exit"))
5033 return;
5035 else if (!strcmp(myARGV[2], "nested") && myARGC >= 4)
5037 char buffer[MAX_PATH + 26];
5038 STARTUPINFOA startup;
5039 PROCESS_INFORMATION info;
5040 HANDLE hFile;
5042 memset(&startup, 0, sizeof(startup));
5043 startup.cb = sizeof(startup);
5044 startup.dwFlags = STARTF_USESHOWWINDOW;
5045 startup.wShowWindow = SW_SHOWNORMAL;
5047 sprintf(buffer, "\"%s\" process dump \"%s\"", selfname, myARGV[3]);
5048 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n");
5049 CloseHandle(info.hProcess);
5050 CloseHandle(info.hThread);
5052 /* The nested process is suspended so we can use the same resource
5053 * file and it's up to the parent to read it before resuming the
5054 * nested process.
5056 hFile = CreateFileA(myARGV[3], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
5057 childPrintf(hFile, "[Nested]\nPid=%08lu\n", info.dwProcessId);
5058 CloseHandle(hFile);
5059 return;
5061 else if (!strcmp(myARGV[2], "parent") && myARGC >= 5)
5063 sscanf(myARGV[4], "%p", &h);
5064 test_parent_process_attribute(atoi(myARGV[3]), h);
5065 return;
5067 else if (!strcmp(myARGV[2], "handlelist") && myARGC >= 5)
5069 sscanf(myARGV[3], "%p", &h);
5070 sscanf(myARGV[4], "%p", &h2);
5071 test_handle_list_attribute(TRUE, h, h2);
5072 return;
5074 else if (!strcmp(myARGV[2], "nested_jobs") && myARGC >= 4)
5076 test_nested_jobs_child(atoi(myARGV[3]));
5077 return;
5080 ok(0, "Unexpected command %s\n", myARGV[2]);
5081 return;
5083 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
5084 if (hproc)
5086 test_process_info(hproc);
5087 CloseHandle(hproc);
5089 else
5090 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
5091 test_process_info(GetCurrentProcess());
5092 test_TerminateProcess();
5093 test_Startup();
5094 test_CommandLine();
5095 test_Directory();
5096 test_Toolhelp();
5097 test_Environment();
5098 test_SuspendFlag();
5099 test_DebuggingFlag();
5100 test_Console();
5101 test_ExitCode();
5102 test_OpenProcess();
5103 test_GetProcessVersion();
5104 test_GetProcessImageFileNameA();
5105 test_QueryFullProcessImageNameA();
5106 test_QueryFullProcessImageNameW();
5107 test_Handles();
5108 test_IsWow64Process();
5109 test_IsWow64Process2();
5110 test_SystemInfo();
5111 test_ProcessorCount();
5112 test_RegistryQuota();
5113 test_DuplicateHandle();
5114 test_StartupNoConsole();
5115 test_DetachConsoleHandles();
5116 test_DetachStdHandles();
5117 test_GetNumaProcessorNode();
5118 test_session_info();
5119 test_GetLogicalProcessorInformationEx();
5120 test_GetSystemCpuSetInformation();
5121 test_largepages();
5122 test_ProcThreadAttributeList();
5123 test_SuspendProcessState();
5124 test_SuspendProcessNewThread();
5125 test_parent_process_attribute(0, NULL);
5126 test_handle_list_attribute(FALSE, NULL, NULL);
5127 test_dead_process();
5128 test_services_exe();
5130 /* things that can be tested:
5131 * lookup: check the way program to be executed is searched
5132 * handles: check the handle inheritance stuff (+sec options)
5133 * console: check if console creation parameters work
5136 if (!pCreateJobObjectW)
5138 win_skip("No job object support\n");
5139 return;
5142 test_IsProcessInJob();
5143 test_TerminateJobObject();
5144 test_QueryInformationJobObject();
5145 test_CompletionPort();
5146 test_KillOnJobClose();
5147 test_WaitForJobObject();
5148 test_nested_jobs();
5149 job = test_AddSelfToJob();
5150 test_jobInheritance(job);
5151 test_job_list_attribute(job);
5152 test_BreakawayOk(job);
5153 CloseHandle(job);