kernel32/tests: Add tests for the register values at process start.
[wine.git] / dlls / kernel32 / tests / process.c
blobe7fe35c8c9a443e2b5769f3f1ce1d9b46f146bef
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"
40 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
41 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
42 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
43 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
45 #define expect_eq_d(expected, actual) \
46 do { \
47 int value = (actual); \
48 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
49 (expected), value); \
50 } while (0)
51 #define expect_eq_s(expected, actual) \
52 do { \
53 LPCSTR value = (actual); \
54 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
55 expected, value); \
56 } while (0)
57 #define expect_eq_ws_i(expected, actual) \
58 do { \
59 LPCWSTR value = (actual); \
60 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
61 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
62 } while (0)
64 static HINSTANCE hkernel32, hntdll;
65 static void (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO);
66 static BOOL (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD);
67 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
68 static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
69 static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
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 BOOL (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process);
75 static BOOL (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result);
76 static BOOL (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code);
77 static BOOL (WINAPI *pQueryInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len, LPDWORD ret_len);
78 static BOOL (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len);
79 static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads);
80 static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR);
81 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
82 static BOOL (WINAPI *pProcessIdToSessionId)(DWORD,DWORD*);
83 static DWORD (WINAPI *pWTSGetActiveConsoleSessionId)(void);
84 static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
85 static BOOL (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*);
86 static BOOL (WINAPI *pProcess32Next)(HANDLE, PROCESSENTRY32*);
87 static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*);
88 static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*);
89 static BOOL (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
90 static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
91 static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
92 static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
93 static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
95 /* ############################### */
96 static char base[MAX_PATH];
97 static char selfname[MAX_PATH];
98 static char* exename;
99 static char resfile[MAX_PATH];
101 static int myARGC;
102 static char** myARGV;
104 /* As some environment variables get very long on Unix, we only test for
105 * the first 127 bytes.
106 * Note that increasing this value past 256 may exceed the buffer size
107 * limitations of the *Profile functions (at least on Wine).
109 #define MAX_LISTED_ENV_VAR 128
111 /* ---------------- portable memory allocation thingie */
113 static char memory[1024*256];
114 static char* memory_index = memory;
116 static char* grab_memory(size_t len)
118 char* ret = memory_index;
119 /* align on dword */
120 len = (len + 3) & ~3;
121 memory_index += len;
122 assert(memory_index <= memory + sizeof(memory));
123 return ret;
126 static void release_memory(void)
128 memory_index = memory;
131 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
133 static const char* encodeA(const char* str)
135 char* ptr;
136 size_t len,i;
138 if (!str) return "";
139 len = strlen(str) + 1;
140 ptr = grab_memory(len * 2 + 1);
141 for (i = 0; i < len; i++)
142 sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
143 ptr[2 * len] = '\0';
144 return ptr;
147 static const char* encodeW(const WCHAR* str)
149 char* ptr;
150 size_t len,i;
152 if (!str) return "";
153 len = lstrlenW(str) + 1;
154 ptr = grab_memory(len * 4 + 1);
155 assert(ptr);
156 for (i = 0; i < len; i++)
157 sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
158 ptr[4 * len] = '\0';
159 return ptr;
162 static unsigned decode_char(char c)
164 if (c >= '0' && c <= '9') return c - '0';
165 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
166 assert(c >= 'A' && c <= 'F');
167 return c - 'A' + 10;
170 static char* decodeA(const char* str)
172 char* ptr;
173 size_t len,i;
175 len = strlen(str) / 2;
176 if (!len--) return NULL;
177 ptr = grab_memory(len + 1);
178 for (i = 0; i < len; i++)
179 ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
180 ptr[len] = '\0';
181 return ptr;
184 /* This will be needed to decode Unicode strings saved by the child process
185 * when we test Unicode functions.
187 static WCHAR* decodeW(const char* str)
189 size_t len;
190 WCHAR* ptr;
191 int i;
193 len = strlen(str) / 4;
194 if (!len--) return NULL;
195 ptr = (WCHAR*)grab_memory(len * 2 + 1);
196 for (i = 0; i < len; i++)
197 ptr[i] = (decode_char(str[4 * i]) << 12) |
198 (decode_char(str[4 * i + 1]) << 8) |
199 (decode_char(str[4 * i + 2]) << 4) |
200 (decode_char(str[4 * i + 3]) << 0);
201 ptr[len] = '\0';
202 return ptr;
205 /******************************************************************
206 * init
208 * generates basic information like:
209 * base: absolute path to curr dir
210 * selfname: the way to reinvoke ourselves
211 * exename: executable without the path
212 * function-pointers, which are not implemented in all windows versions
214 static BOOL init(void)
216 char *p;
218 myARGC = winetest_get_mainargs( &myARGV );
219 if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
220 strcpy(selfname, myARGV[0]);
222 /* Strip the path of selfname */
223 if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1;
224 else exename = selfname;
226 if ((p = strrchr(exename, '/')) != NULL) exename = p + 1;
228 hkernel32 = GetModuleHandleA("kernel32");
229 hntdll = GetModuleHandleA("ntdll.dll");
231 pNtQueryInformationProcess = (void *)GetProcAddress(hntdll, "NtQueryInformationProcess");
233 pGetNativeSystemInfo = (void *) GetProcAddress(hkernel32, "GetNativeSystemInfo");
234 pGetSystemRegistryQuota = (void *) GetProcAddress(hkernel32, "GetSystemRegistryQuota");
235 pIsWow64Process = (void *) GetProcAddress(hkernel32, "IsWow64Process");
236 pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
237 pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
238 pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA");
239 pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW");
240 pK32GetProcessImageFileNameA = (void *) GetProcAddress(hkernel32, "K32GetProcessImageFileNameA");
241 pCreateJobObjectW = (void *)GetProcAddress(hkernel32, "CreateJobObjectW");
242 pAssignProcessToJobObject = (void *)GetProcAddress(hkernel32, "AssignProcessToJobObject");
243 pIsProcessInJob = (void *)GetProcAddress(hkernel32, "IsProcessInJob");
244 pTerminateJobObject = (void *)GetProcAddress(hkernel32, "TerminateJobObject");
245 pQueryInformationJobObject = (void *)GetProcAddress(hkernel32, "QueryInformationJobObject");
246 pSetInformationJobObject = (void *)GetProcAddress(hkernel32, "SetInformationJobObject");
247 pCreateIoCompletionPort = (void *)GetProcAddress(hkernel32, "CreateIoCompletionPort");
248 pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode");
249 pProcessIdToSessionId = (void *)GetProcAddress(hkernel32, "ProcessIdToSessionId");
250 pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId");
251 pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
252 pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First");
253 pProcess32Next = (void *)GetProcAddress(hkernel32, "Process32Next");
254 pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First");
255 pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next");
256 pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
257 pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum");
258 pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
259 pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
260 pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
262 return TRUE;
265 /******************************************************************
266 * get_file_name
268 * generates an absolute file_name for temporary file
271 static void get_file_name(char* buf)
273 char path[MAX_PATH];
275 buf[0] = '\0';
276 GetTempPathA(sizeof(path), path);
277 GetTempFileNameA(path, "wt", 0, buf);
280 /******************************************************************
281 * static void childPrintf
284 static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...)
286 va_list valist;
287 char buffer[1024+4*MAX_LISTED_ENV_VAR];
288 DWORD w;
290 va_start(valist, fmt);
291 vsprintf(buffer, fmt, valist);
292 va_end(valist);
293 WriteFile(h, buffer, strlen(buffer), &w, NULL);
297 /******************************************************************
298 * doChild
300 * output most of the information in the child process
302 static void doChild(const char* file, const char* option)
304 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
305 STARTUPINFOA siA;
306 STARTUPINFOW siW;
307 int i;
308 char *ptrA, *ptrA_save;
309 WCHAR *ptrW, *ptrW_save;
310 char bufA[MAX_PATH];
311 WCHAR bufW[MAX_PATH];
312 HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
313 HANDLE snapshot;
314 PROCESSENTRY32 pe;
315 BOOL ret;
317 if (hFile == INVALID_HANDLE_VALUE) return;
319 /* output of startup info (Ansi) */
320 GetStartupInfoA(&siA);
321 childPrintf(hFile,
322 "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
323 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
324 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
325 "dwFlags=%u\nwShowWindow=%u\n"
326 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
327 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
328 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize,
329 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute,
330 siA.dwFlags, siA.wShowWindow,
331 (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError);
333 /* check the console handles in the TEB */
334 childPrintf(hFile, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
335 (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput,
336 (DWORD_PTR)params->hStdError);
338 /* since GetStartupInfoW is only implemented in win2k,
339 * zero out before calling so we can notice the difference
341 memset(&siW, 0, sizeof(siW));
342 GetStartupInfoW(&siW);
343 childPrintf(hFile,
344 "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
345 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
346 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
347 "dwFlags=%u\nwShowWindow=%u\n"
348 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
349 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
350 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize,
351 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute,
352 siW.dwFlags, siW.wShowWindow,
353 (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError);
355 /* Arguments */
356 childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
357 for (i = 0; i < myARGC; i++)
359 childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
361 childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
362 childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
364 /* output toolhelp information */
365 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
366 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
367 memset(&pe, 0, sizeof(pe));
368 pe.dwSize = sizeof(pe);
369 if (pProcess32First(snapshot, &pe))
371 while (pe.th32ProcessID != GetCurrentProcessId())
372 if (!pProcess32Next(snapshot, &pe)) break;
374 CloseHandle(snapshot);
375 ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n");
376 childPrintf(hFile,
377 "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n"
378 "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n"
379 "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n",
380 pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID,
381 pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase,
382 pe.dwFlags, encodeA(pe.szExeFile));
384 /* output of environment (Ansi) */
385 ptrA_save = ptrA = GetEnvironmentStringsA();
386 if (ptrA)
388 char env_var[MAX_LISTED_ENV_VAR];
390 childPrintf(hFile, "[EnvironmentA]\n");
391 i = 0;
392 while (*ptrA)
394 lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR);
395 childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
396 i++;
397 ptrA += strlen(ptrA) + 1;
399 childPrintf(hFile, "len=%d\n\n", i);
400 FreeEnvironmentStringsA(ptrA_save);
403 /* output of environment (Unicode) */
404 ptrW_save = ptrW = GetEnvironmentStringsW();
405 if (ptrW)
407 WCHAR env_var[MAX_LISTED_ENV_VAR];
409 childPrintf(hFile, "[EnvironmentW]\n");
410 i = 0;
411 while (*ptrW)
413 lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1);
414 env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
415 childPrintf(hFile, "env%d=%s\n", i, encodeW(env_var));
416 i++;
417 ptrW += lstrlenW(ptrW) + 1;
419 childPrintf(hFile, "len=%d\n\n", i);
420 FreeEnvironmentStringsW(ptrW_save);
423 childPrintf(hFile, "[Misc]\n");
424 if (GetCurrentDirectoryA(sizeof(bufA), bufA))
425 childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
426 if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW))
427 childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
428 childPrintf(hFile, "\n");
430 if (option && strcmp(option, "console") == 0)
432 CONSOLE_SCREEN_BUFFER_INFO sbi;
433 HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE);
434 HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
435 DWORD modeIn, modeOut;
437 childPrintf(hFile, "[Console]\n");
438 if (GetConsoleScreenBufferInfo(hConOut, &sbi))
440 childPrintf(hFile, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
441 sbi.dwSize.X, sbi.dwSize.Y, sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y, sbi.wAttributes);
442 childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
443 sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom);
444 childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n",
445 sbi.dwMaximumWindowSize.X, sbi.dwMaximumWindowSize.Y);
447 childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
448 GetConsoleCP(), GetConsoleOutputCP());
449 if (GetConsoleMode(hConIn, &modeIn))
450 childPrintf(hFile, "InputMode=%u\n", modeIn);
451 if (GetConsoleMode(hConOut, &modeOut))
452 childPrintf(hFile, "OutputMode=%u\n", modeOut);
454 /* now that we have written all relevant information, let's change it */
455 SetLastError(0xdeadbeef);
456 ret = SetConsoleCP(1252);
457 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
459 win_skip("Setting the codepage is not implemented\n");
461 else
463 ok(ret, "Setting CP\n");
464 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
467 ret = SetConsoleMode(hConIn, modeIn ^ 1);
468 ok( ret, "Setting mode (%d)\n", GetLastError());
469 ret = SetConsoleMode(hConOut, modeOut ^ 1);
470 ok( ret, "Setting mode (%d)\n", GetLastError());
471 sbi.dwCursorPosition.X ^= 1;
472 sbi.dwCursorPosition.Y ^= 1;
473 ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition);
474 ok( ret, "Setting cursor position (%d)\n", GetLastError());
476 if (option && strcmp(option, "stdhandle") == 0)
478 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
479 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
481 if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE)
483 char buf[1024];
484 DWORD r, w;
486 ok(ReadFile(hStdIn, buf, sizeof(buf), &r, NULL) && r > 0, "Reading message from input pipe\n");
487 childPrintf(hFile, "[StdHandle]\nmsg=%s\n\n", encodeA(buf));
488 ok(WriteFile(hStdOut, buf, r, &w, NULL) && w == r, "Writing message to output pipe\n");
492 if (option && strcmp(option, "exit_code") == 0)
494 childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123);
495 CloseHandle(hFile);
496 ExitProcess(123);
499 CloseHandle(hFile);
502 static char* getChildString(const char* sect, const char* key)
504 char buf[1024+4*MAX_LISTED_ENV_VAR];
505 char* ret;
507 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
508 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
509 assert(!(strlen(buf) & 1));
510 ret = decodeA(buf);
511 return ret;
514 static WCHAR* getChildStringW(const char* sect, const char* key)
516 char buf[1024+4*MAX_LISTED_ENV_VAR];
517 WCHAR* ret;
519 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
520 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
521 assert(!(strlen(buf) & 1));
522 ret = decodeW(buf);
523 return ret;
526 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
527 * others... (windows uses stricmp while Un*x uses strcasecmp...)
529 static int wtstrcasecmp(const char* p1, const char* p2)
531 char c1, c2;
533 c1 = c2 = '@';
534 while (c1 == c2 && c1)
536 c1 = *p1++; c2 = *p2++;
537 if (c1 != c2)
539 c1 = toupper(c1); c2 = toupper(c2);
542 return c1 - c2;
545 static int strCmp(const char* s1, const char* s2, BOOL sensitive)
547 if (!s1 && !s2) return 0;
548 if (!s2) return -1;
549 if (!s1) return 1;
550 return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2);
553 static void ok_child_string( int line, const char *sect, const char *key,
554 const char *expect, int sensitive )
556 char* result = getChildString( sect, key );
557 ok_(__FILE__, line)( strCmp(result, expect, sensitive) == 0, "%s:%s expected '%s', got '%s'\n",
558 sect, key, expect ? expect : "(null)", result );
561 static void ok_child_stringWA( int line, const char *sect, const char *key,
562 const char *expect, int sensitive )
564 WCHAR* expectW;
565 CHAR* resultA;
566 DWORD len;
567 WCHAR* result = getChildStringW( sect, key );
569 len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0);
570 expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
571 MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len);
573 len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL);
574 resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR));
575 WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL);
577 if (sensitive)
578 ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
579 sect, key, expect ? expect : "(null)", resultA );
580 else
581 ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
582 sect, key, expect ? expect : "(null)", resultA );
583 HeapFree(GetProcessHeap(),0,expectW);
584 HeapFree(GetProcessHeap(),0,resultA);
587 static void ok_child_int( int line, const char *sect, const char *key, UINT expect )
589 UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile );
590 ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result );
593 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
594 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
595 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
596 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
598 static void test_Startup(void)
600 char buffer[MAX_PATH];
601 PROCESS_INFORMATION info;
602 STARTUPINFOA startup,si;
603 char *result;
604 static CHAR title[] = "I'm the title string",
605 desktop[] = "winsta0\\default",
606 empty[] = "";
608 /* let's start simplistic */
609 memset(&startup, 0, sizeof(startup));
610 startup.cb = sizeof(startup);
611 startup.dwFlags = STARTF_USESHOWWINDOW;
612 startup.wShowWindow = SW_SHOWNORMAL;
614 get_file_name(resfile);
615 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
616 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
617 /* wait for child to terminate */
618 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
619 /* child process has changed result file, so let profile functions know about it */
620 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
622 GetStartupInfoA(&si);
623 okChildInt("StartupInfoA", "cb", startup.cb);
624 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
625 okChildInt("StartupInfoA", "dwX", startup.dwX);
626 okChildInt("StartupInfoA", "dwY", startup.dwY);
627 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
628 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
629 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
630 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
631 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
632 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
633 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
634 release_memory();
635 DeleteFileA(resfile);
637 /* not so simplistic now */
638 memset(&startup, 0, sizeof(startup));
639 startup.cb = sizeof(startup);
640 startup.dwFlags = STARTF_USESHOWWINDOW;
641 startup.wShowWindow = SW_SHOWNORMAL;
642 startup.lpTitle = title;
643 startup.lpDesktop = desktop;
644 startup.dwXCountChars = 0x12121212;
645 startup.dwYCountChars = 0x23232323;
646 startup.dwX = 0x34343434;
647 startup.dwY = 0x45454545;
648 startup.dwXSize = 0x56565656;
649 startup.dwYSize = 0x67676767;
650 startup.dwFillAttribute = 0xA55A;
652 get_file_name(resfile);
653 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
654 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
655 /* wait for child to terminate */
656 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
657 /* child process has changed result file, so let profile functions know about it */
658 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
660 okChildInt("StartupInfoA", "cb", startup.cb);
661 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
662 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
663 okChildInt("StartupInfoA", "dwX", startup.dwX);
664 okChildInt("StartupInfoA", "dwY", startup.dwY);
665 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
666 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
667 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
668 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
669 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
670 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
671 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
672 release_memory();
673 DeleteFileA(resfile);
675 /* not so simplistic now */
676 memset(&startup, 0, sizeof(startup));
677 startup.cb = sizeof(startup);
678 startup.dwFlags = STARTF_USESHOWWINDOW;
679 startup.wShowWindow = SW_SHOWNORMAL;
680 startup.lpTitle = title;
681 startup.lpDesktop = NULL;
682 startup.dwXCountChars = 0x12121212;
683 startup.dwYCountChars = 0x23232323;
684 startup.dwX = 0x34343434;
685 startup.dwY = 0x45454545;
686 startup.dwXSize = 0x56565656;
687 startup.dwYSize = 0x67676767;
688 startup.dwFillAttribute = 0xA55A;
690 get_file_name(resfile);
691 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
692 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
693 /* wait for child to terminate */
694 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
695 /* child process has changed result file, so let profile functions know about it */
696 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
698 okChildInt("StartupInfoA", "cb", startup.cb);
699 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
700 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
701 okChildInt("StartupInfoA", "dwX", startup.dwX);
702 okChildInt("StartupInfoA", "dwY", startup.dwY);
703 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
704 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
705 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
706 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
707 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
708 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
709 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
710 release_memory();
711 DeleteFileA(resfile);
713 /* not so simplistic now */
714 memset(&startup, 0, sizeof(startup));
715 startup.cb = sizeof(startup);
716 startup.dwFlags = STARTF_USESHOWWINDOW;
717 startup.wShowWindow = SW_SHOWNORMAL;
718 startup.lpTitle = title;
719 startup.lpDesktop = empty;
720 startup.dwXCountChars = 0x12121212;
721 startup.dwYCountChars = 0x23232323;
722 startup.dwX = 0x34343434;
723 startup.dwY = 0x45454545;
724 startup.dwXSize = 0x56565656;
725 startup.dwYSize = 0x67676767;
726 startup.dwFillAttribute = 0xA55A;
728 get_file_name(resfile);
729 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
730 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
731 /* wait for child to terminate */
732 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
733 /* child process has changed result file, so let profile functions know about it */
734 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
736 okChildInt("StartupInfoA", "cb", startup.cb);
737 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
738 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
739 okChildInt("StartupInfoA", "dwX", startup.dwX);
740 okChildInt("StartupInfoA", "dwY", startup.dwY);
741 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
742 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
743 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
744 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
745 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
746 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
747 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
748 release_memory();
749 DeleteFileA(resfile);
751 /* not so simplistic now */
752 memset(&startup, 0, sizeof(startup));
753 startup.cb = sizeof(startup);
754 startup.dwFlags = STARTF_USESHOWWINDOW;
755 startup.wShowWindow = SW_SHOWNORMAL;
756 startup.lpTitle = NULL;
757 startup.lpDesktop = desktop;
758 startup.dwXCountChars = 0x12121212;
759 startup.dwYCountChars = 0x23232323;
760 startup.dwX = 0x34343434;
761 startup.dwY = 0x45454545;
762 startup.dwXSize = 0x56565656;
763 startup.dwYSize = 0x67676767;
764 startup.dwFillAttribute = 0xA55A;
766 get_file_name(resfile);
767 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
768 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
769 /* wait for child to terminate */
770 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
771 /* child process has changed result file, so let profile functions know about it */
772 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
774 okChildInt("StartupInfoA", "cb", startup.cb);
775 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
776 result = getChildString( "StartupInfoA", "lpTitle" );
777 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
778 "expected '%s' or null, got '%s'\n", selfname, result );
779 okChildInt("StartupInfoA", "dwX", startup.dwX);
780 okChildInt("StartupInfoA", "dwY", startup.dwY);
781 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
782 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
783 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
784 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
785 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
786 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
787 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
788 release_memory();
789 DeleteFileA(resfile);
791 /* not so simplistic now */
792 memset(&startup, 0, sizeof(startup));
793 startup.cb = sizeof(startup);
794 startup.dwFlags = STARTF_USESHOWWINDOW;
795 startup.wShowWindow = SW_SHOWNORMAL;
796 startup.lpTitle = empty;
797 startup.lpDesktop = desktop;
798 startup.dwXCountChars = 0x12121212;
799 startup.dwYCountChars = 0x23232323;
800 startup.dwX = 0x34343434;
801 startup.dwY = 0x45454545;
802 startup.dwXSize = 0x56565656;
803 startup.dwYSize = 0x67676767;
804 startup.dwFillAttribute = 0xA55A;
806 get_file_name(resfile);
807 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
808 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
809 /* wait for child to terminate */
810 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
811 /* child process has changed result file, so let profile functions know about it */
812 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
814 okChildInt("StartupInfoA", "cb", startup.cb);
815 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
816 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
817 okChildInt("StartupInfoA", "dwX", startup.dwX);
818 okChildInt("StartupInfoA", "dwY", startup.dwY);
819 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
820 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
821 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
822 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
823 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
824 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
825 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
826 release_memory();
827 DeleteFileA(resfile);
829 /* not so simplistic now */
830 memset(&startup, 0, sizeof(startup));
831 startup.cb = sizeof(startup);
832 startup.dwFlags = STARTF_USESHOWWINDOW;
833 startup.wShowWindow = SW_SHOWNORMAL;
834 startup.lpTitle = empty;
835 startup.lpDesktop = empty;
836 startup.dwXCountChars = 0x12121212;
837 startup.dwYCountChars = 0x23232323;
838 startup.dwX = 0x34343434;
839 startup.dwY = 0x45454545;
840 startup.dwXSize = 0x56565656;
841 startup.dwYSize = 0x67676767;
842 startup.dwFillAttribute = 0xA55A;
844 get_file_name(resfile);
845 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
846 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
847 /* wait for child to terminate */
848 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
849 /* child process has changed result file, so let profile functions know about it */
850 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
852 okChildInt("StartupInfoA", "cb", startup.cb);
853 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
854 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
855 okChildInt("StartupInfoA", "dwX", startup.dwX);
856 okChildInt("StartupInfoA", "dwY", startup.dwY);
857 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
858 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
859 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
860 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
861 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
862 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
863 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
864 release_memory();
865 DeleteFileA(resfile);
867 /* TODO: test for A/W and W/A and W/W */
870 static void test_CommandLine(void)
872 char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
873 char buffer2[MAX_PATH];
874 PROCESS_INFORMATION info;
875 STARTUPINFOA startup;
876 BOOL ret;
878 memset(&startup, 0, sizeof(startup));
879 startup.cb = sizeof(startup);
880 startup.dwFlags = STARTF_USESHOWWINDOW;
881 startup.wShowWindow = SW_SHOWNORMAL;
883 /* the basics */
884 get_file_name(resfile);
885 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
886 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
887 /* wait for child to terminate */
888 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
889 /* child process has changed result file, so let profile functions know about it */
890 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
892 okChildInt("Arguments", "argcA", 5);
893 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
894 okChildString("Arguments", "argvA5", NULL);
895 okChildString("Arguments", "CommandLineA", buffer);
896 release_memory();
897 DeleteFileA(resfile);
899 memset(&startup, 0, sizeof(startup));
900 startup.cb = sizeof(startup);
901 startup.dwFlags = STARTF_USESHOWWINDOW;
902 startup.wShowWindow = SW_SHOWNORMAL;
904 /* from François */
905 get_file_name(resfile);
906 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
907 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
908 /* wait for child to terminate */
909 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
910 /* child process has changed result file, so let profile functions know about it */
911 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
913 okChildInt("Arguments", "argcA", 7);
914 okChildString("Arguments", "argvA4", "a\"b\\");
915 okChildString("Arguments", "argvA5", "c\"");
916 okChildString("Arguments", "argvA6", "d");
917 okChildString("Arguments", "argvA7", NULL);
918 okChildString("Arguments", "CommandLineA", buffer);
919 release_memory();
920 DeleteFileA(resfile);
922 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
923 get_file_name(resfile);
924 /* Use exename to avoid buffer containing things like 'C:' */
925 sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
926 SetLastError(0xdeadbeef);
927 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
928 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
929 /* wait for child to terminate */
930 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
931 /* child process has changed result file, so let profile functions know about it */
932 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
933 sprintf(buffer, "./%s", exename);
934 okChildString("Arguments", "argvA0", buffer);
935 release_memory();
936 DeleteFileA(resfile);
938 get_file_name(resfile);
939 /* Use exename to avoid buffer containing things like 'C:' */
940 sprintf(buffer, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
941 SetLastError(0xdeadbeef);
942 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
943 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
944 /* wait for child to terminate */
945 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
946 /* child process has changed result file, so let profile functions know about it */
947 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
948 sprintf(buffer, ".\\%s", exename);
949 okChildString("Arguments", "argvA0", buffer);
950 release_memory();
951 DeleteFileA(resfile);
953 get_file_name(resfile);
954 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
955 assert ( lpFilePart != 0);
956 *(lpFilePart -1 ) = 0;
957 p = strrchr(fullpath, '\\');
958 /* Use exename to avoid buffer containing things like 'C:' */
959 if (p) sprintf(buffer, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p, exename, resfile);
960 else sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
961 SetLastError(0xdeadbeef);
962 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
963 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
964 /* wait for child to terminate */
965 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
966 /* child process has changed result file, so let profile functions know about it */
967 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
968 if (p) sprintf(buffer, "..%s/%s", p, exename);
969 else sprintf(buffer, "./%s", exename);
970 okChildString("Arguments", "argvA0", buffer);
971 release_memory();
972 DeleteFileA(resfile);
974 /* Using AppName */
975 get_file_name(resfile);
976 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
977 assert ( lpFilePart != 0);
978 *(lpFilePart -1 ) = 0;
979 p = strrchr(fullpath, '\\');
980 /* Use exename to avoid buffer containing things like 'C:' */
981 if (p) sprintf(buffer, "..%s/%s", p, exename);
982 else sprintf(buffer, "./%s", exename);
983 sprintf(buffer2, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile);
984 SetLastError(0xdeadbeef);
985 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
986 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
987 /* wait for child to terminate */
988 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
989 /* child process has changed result file, so let profile functions know about it */
990 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
991 sprintf(buffer, "tests/process.c dump %s", resfile);
992 okChildString("Arguments", "argvA0", "dummy");
993 okChildString("Arguments", "CommandLineA", buffer2);
994 okChildStringWA("Arguments", "CommandLineW", buffer2);
995 release_memory();
996 DeleteFileA(resfile);
998 if (0) /* Test crashes on NT-based Windows. */
1000 /* Test NULL application name and command line parameters. */
1001 SetLastError(0xdeadbeef);
1002 ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1003 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1004 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1005 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1008 buffer[0] = '\0';
1010 /* Test empty application name parameter. */
1011 SetLastError(0xdeadbeef);
1012 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1013 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1014 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1015 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1016 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1017 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1019 buffer2[0] = '\0';
1021 /* Test empty application name and command line parameters. */
1022 SetLastError(0xdeadbeef);
1023 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1024 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1025 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1026 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1027 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1028 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1030 /* Test empty command line parameter. */
1031 SetLastError(0xdeadbeef);
1032 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1033 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1034 ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
1035 GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ ||
1036 GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ ||
1037 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */,
1038 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1040 strcpy(buffer, "doesnotexist.exe");
1041 strcpy(buffer2, "does not exist.exe");
1043 /* Test nonexistent application name. */
1044 SetLastError(0xdeadbeef);
1045 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1046 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1047 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1049 SetLastError(0xdeadbeef);
1050 ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1051 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1052 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1054 /* Test nonexistent command line parameter. */
1055 SetLastError(0xdeadbeef);
1056 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1057 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1058 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1060 SetLastError(0xdeadbeef);
1061 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1062 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1063 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1066 static void test_Directory(void)
1068 char buffer[MAX_PATH];
1069 PROCESS_INFORMATION info;
1070 STARTUPINFOA startup;
1071 char windir[MAX_PATH];
1072 static CHAR cmdline[] = "winver.exe";
1074 memset(&startup, 0, sizeof(startup));
1075 startup.cb = sizeof(startup);
1076 startup.dwFlags = STARTF_USESHOWWINDOW;
1077 startup.wShowWindow = SW_SHOWNORMAL;
1079 /* the basics */
1080 get_file_name(resfile);
1081 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1082 GetWindowsDirectoryA( windir, sizeof(windir) );
1083 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n");
1084 /* wait for child to terminate */
1085 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1086 /* child process has changed result file, so let profile functions know about it */
1087 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1089 okChildIString("Misc", "CurrDirA", windir);
1090 release_memory();
1091 DeleteFileA(resfile);
1093 /* search PATH for the exe if directory is NULL */
1094 ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1095 ok(TerminateProcess(info.hProcess, 0), "Child process termination\n");
1097 /* if any directory is provided, don't search PATH, error on bad directory */
1098 SetLastError(0xdeadbeef);
1099 memset(&info, 0, sizeof(info));
1100 ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L,
1101 NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n");
1102 ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1103 ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n");
1106 static void test_Toolhelp(void)
1108 char buffer[MAX_PATH];
1109 STARTUPINFOA startup;
1110 PROCESS_INFORMATION info;
1111 HANDLE process, thread, snapshot;
1112 PROCESSENTRY32 pe;
1113 THREADENTRY32 te;
1114 DWORD ret;
1115 int i;
1117 memset(&startup, 0, sizeof(startup));
1118 startup.cb = sizeof(startup);
1119 startup.dwFlags = STARTF_USESHOWWINDOW;
1120 startup.wShowWindow = SW_SHOWNORMAL;
1122 get_file_name(resfile);
1123 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1124 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1125 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1126 CloseHandle(info.hProcess);
1127 CloseHandle(info.hThread);
1129 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1130 okChildInt("Toolhelp", "cntUsage", 0);
1131 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1132 okChildInt("Toolhelp", "th32ModuleID", 0);
1133 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1134 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1135 okChildInt("Toolhelp", "dwFlags", 0);
1137 release_memory();
1138 DeleteFileA(resfile);
1140 get_file_name(resfile);
1141 sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile);
1142 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1143 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1145 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1146 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1147 CloseHandle(process);
1149 CloseHandle(info.hProcess);
1150 CloseHandle(info.hThread);
1152 for (i = 0; i < 20; i++)
1154 SetLastError(0xdeadbeef);
1155 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1156 ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError());
1157 if (!process) break;
1158 CloseHandle(process);
1159 Sleep(100);
1161 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1162 ok(i < 20 || broken(i == 20), "process object not released\n");
1164 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1165 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1166 memset(&pe, 0, sizeof(pe));
1167 pe.dwSize = sizeof(pe);
1168 if (pProcess32First(snapshot, &pe))
1170 while (pe.th32ParentProcessID != info.dwProcessId)
1171 if (!pProcess32Next(snapshot, &pe)) break;
1173 CloseHandle(snapshot);
1174 ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n");
1176 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID);
1177 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1179 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1180 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1181 memset(&te, 0, sizeof(te));
1182 te.dwSize = sizeof(te);
1183 if (pThread32First(snapshot, &te))
1185 while (te.th32OwnerProcessID != pe.th32ProcessID)
1186 if (!pThread32Next(snapshot, &te)) break;
1188 CloseHandle(snapshot);
1189 ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1191 thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID);
1192 ok(thread != NULL, "OpenThread failed %u\n", GetLastError());
1193 ret = ResumeThread(thread);
1194 ok(ret == 1, "expected 1, got %u\n", ret);
1195 CloseHandle(thread);
1197 ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1198 CloseHandle(process);
1200 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1201 okChildInt("Toolhelp", "cntUsage", 0);
1202 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1203 okChildInt("Toolhelp", "th32ModuleID", 0);
1204 okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1205 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1206 okChildInt("Toolhelp", "dwFlags", 0);
1208 release_memory();
1209 DeleteFileA(resfile);
1212 static BOOL is_str_env_drive_dir(const char* str)
1214 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1215 str[3] == '=' && str[4] == str[1];
1218 /* compared expected child's environment (in gesA) from actual
1219 * environment our child got
1221 static void cmpEnvironment(const char* gesA)
1223 int i, clen;
1224 const char* ptrA;
1225 char* res;
1226 char key[32];
1227 BOOL found;
1229 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1231 /* now look each parent env in child */
1232 if ((ptrA = gesA) != NULL)
1234 while (*ptrA)
1236 for (i = 0; i < clen; i++)
1238 sprintf(key, "env%d", i);
1239 res = getChildString("EnvironmentA", key);
1240 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1241 break;
1243 found = i < clen;
1244 ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1246 ptrA += strlen(ptrA) + 1;
1247 release_memory();
1250 /* and each child env in parent */
1251 for (i = 0; i < clen; i++)
1253 sprintf(key, "env%d", i);
1254 res = getChildString("EnvironmentA", key);
1255 if ((ptrA = gesA) != NULL)
1257 while (*ptrA)
1259 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1260 break;
1261 ptrA += strlen(ptrA) + 1;
1263 if (!*ptrA) ptrA = NULL;
1266 if (!is_str_env_drive_dir(res))
1268 found = ptrA != NULL;
1269 ok(found, "Child-env string %s isn't in parent process\n", res);
1271 /* else => should also test we get the right per drive default directory here... */
1275 static void test_Environment(void)
1277 char buffer[MAX_PATH];
1278 PROCESS_INFORMATION info;
1279 STARTUPINFOA startup;
1280 char *child_env;
1281 int child_env_len;
1282 char *ptr;
1283 char *ptr2;
1284 char *env;
1285 int slen;
1287 memset(&startup, 0, sizeof(startup));
1288 startup.cb = sizeof(startup);
1289 startup.dwFlags = STARTF_USESHOWWINDOW;
1290 startup.wShowWindow = SW_SHOWNORMAL;
1292 /* the basics */
1293 get_file_name(resfile);
1294 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1295 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1296 /* wait for child to terminate */
1297 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1298 /* child process has changed result file, so let profile functions know about it */
1299 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1301 env = GetEnvironmentStringsA();
1302 cmpEnvironment(env);
1303 release_memory();
1304 DeleteFileA(resfile);
1306 memset(&startup, 0, sizeof(startup));
1307 startup.cb = sizeof(startup);
1308 startup.dwFlags = STARTF_USESHOWWINDOW;
1309 startup.wShowWindow = SW_SHOWNORMAL;
1311 /* the basics */
1312 get_file_name(resfile);
1313 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1315 child_env_len = 0;
1316 ptr = env;
1317 while(*ptr)
1319 slen = strlen(ptr)+1;
1320 child_env_len += slen;
1321 ptr += slen;
1323 /* Add space for additional environment variables */
1324 child_env_len += 256;
1325 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1327 ptr = child_env;
1328 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1329 ptr += strlen(ptr) + 1;
1330 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1331 ptr += strlen(ptr) + 1;
1332 strcpy(ptr, "FOO=BAR");
1333 ptr += strlen(ptr) + 1;
1334 strcpy(ptr, "BAR=FOOBAR");
1335 ptr += strlen(ptr) + 1;
1336 /* copy all existing variables except:
1337 * - WINELOADER
1338 * - PATH (already set above)
1339 * - the directory definitions (=[A-Z]:=)
1341 for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1343 if (strncmp(ptr2, "PATH=", 5) != 0 &&
1344 strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1345 !is_str_env_drive_dir(ptr2))
1347 strcpy(ptr, ptr2);
1348 ptr += strlen(ptr) + 1;
1351 *ptr = '\0';
1352 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1353 /* wait for child to terminate */
1354 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1355 /* child process has changed result file, so let profile functions know about it */
1356 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1358 cmpEnvironment(child_env);
1360 HeapFree(GetProcessHeap(), 0, child_env);
1361 FreeEnvironmentStringsA(env);
1362 release_memory();
1363 DeleteFileA(resfile);
1366 static void test_SuspendFlag(void)
1368 char buffer[MAX_PATH];
1369 PROCESS_INFORMATION info;
1370 STARTUPINFOA startup, us;
1371 DWORD exit_status;
1372 char *result;
1374 /* let's start simplistic */
1375 memset(&startup, 0, sizeof(startup));
1376 startup.cb = sizeof(startup);
1377 startup.dwFlags = STARTF_USESHOWWINDOW;
1378 startup.wShowWindow = SW_SHOWNORMAL;
1380 get_file_name(resfile);
1381 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1382 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1384 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1385 Sleep(1000);
1386 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1387 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1389 /* wait for child to terminate */
1390 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1391 /* child process has changed result file, so let profile functions know about it */
1392 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1394 GetStartupInfoA(&us);
1396 okChildInt("StartupInfoA", "cb", startup.cb);
1397 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1398 result = getChildString( "StartupInfoA", "lpTitle" );
1399 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1400 "expected '%s' or null, got '%s'\n", selfname, result );
1401 okChildInt("StartupInfoA", "dwX", startup.dwX);
1402 okChildInt("StartupInfoA", "dwY", startup.dwY);
1403 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1404 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1405 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1406 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1407 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1408 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1409 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1410 release_memory();
1411 DeleteFileA(resfile);
1414 static void test_DebuggingFlag(void)
1416 char buffer[MAX_PATH];
1417 void *processbase = NULL;
1418 PROCESS_INFORMATION info;
1419 STARTUPINFOA startup, us;
1420 DEBUG_EVENT de;
1421 unsigned dbg = 0;
1422 char *result;
1424 /* let's start simplistic */
1425 memset(&startup, 0, sizeof(startup));
1426 startup.cb = sizeof(startup);
1427 startup.dwFlags = STARTF_USESHOWWINDOW;
1428 startup.wShowWindow = SW_SHOWNORMAL;
1430 get_file_name(resfile);
1431 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1432 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1434 /* get all startup events up to the entry point break exception */
1437 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1438 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1439 if (!dbg)
1441 ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1442 "first event: %d\n", de.dwDebugEventCode);
1443 processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1445 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1446 ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT ||
1447 de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1448 } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1450 ok(dbg, "I have seen a debug event\n");
1451 /* wait for child to terminate */
1452 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1453 /* child process has changed result file, so let profile functions know about it */
1454 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1456 GetStartupInfoA(&us);
1458 okChildInt("StartupInfoA", "cb", startup.cb);
1459 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1460 result = getChildString( "StartupInfoA", "lpTitle" );
1461 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1462 "expected '%s' or null, got '%s'\n", selfname, result );
1463 okChildInt("StartupInfoA", "dwX", startup.dwX);
1464 okChildInt("StartupInfoA", "dwY", startup.dwY);
1465 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1466 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1467 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1468 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1469 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1470 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1471 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1472 release_memory();
1473 DeleteFileA(resfile);
1476 static BOOL is_console(HANDLE h)
1478 return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1481 static void test_Console(void)
1483 char buffer[MAX_PATH];
1484 PROCESS_INFORMATION info;
1485 STARTUPINFOA startup, us;
1486 SECURITY_ATTRIBUTES sa;
1487 CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC;
1488 DWORD modeIn, modeOut, modeInC, modeOutC;
1489 DWORD cpIn, cpOut, cpInC, cpOutC;
1490 DWORD w;
1491 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1492 const char* msg = "This is a std-handle inheritance test.";
1493 unsigned msg_len;
1494 BOOL run_tests = TRUE;
1495 char *result;
1497 memset(&startup, 0, sizeof(startup));
1498 startup.cb = sizeof(startup);
1499 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1500 startup.wShowWindow = SW_SHOWNORMAL;
1502 sa.nLength = sizeof(sa);
1503 sa.lpSecurityDescriptor = NULL;
1504 sa.bInheritHandle = TRUE;
1506 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1507 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1509 /* first, we need to be sure we're attached to a console */
1510 if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1512 /* we're not attached to a console, let's do it */
1513 AllocConsole();
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 /* now verify everything's ok */
1518 ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1519 ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1520 startup.hStdError = startup.hStdOutput;
1522 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1523 ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1524 ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1525 cpIn = GetConsoleCP();
1526 cpOut = GetConsoleOutputCP();
1528 get_file_name(resfile);
1529 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile);
1530 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1532 /* wait for child to terminate */
1533 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1534 /* child process has changed result file, so let profile functions know about it */
1535 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1537 /* now get the modification the child has made, and resets parents expected values */
1538 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1539 ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1540 ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1542 SetConsoleMode(startup.hStdInput, modeIn);
1543 SetConsoleMode(startup.hStdOutput, modeOut);
1545 cpInC = GetConsoleCP();
1546 cpOutC = GetConsoleOutputCP();
1548 /* Try to set invalid CP */
1549 SetLastError(0xdeadbeef);
1550 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1551 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1552 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1553 "GetLastError: expecting %u got %u\n",
1554 ERROR_INVALID_PARAMETER, GetLastError());
1555 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1556 run_tests = FALSE;
1559 SetLastError(0xdeadbeef);
1560 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1561 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1562 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1563 "GetLastError: expecting %u got %u\n",
1564 ERROR_INVALID_PARAMETER, GetLastError());
1566 SetConsoleCP(cpIn);
1567 SetConsoleOutputCP(cpOut);
1569 GetStartupInfoA(&us);
1571 okChildInt("StartupInfoA", "cb", startup.cb);
1572 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1573 result = getChildString( "StartupInfoA", "lpTitle" );
1574 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1575 "expected '%s' or null, got '%s'\n", selfname, result );
1576 okChildInt("StartupInfoA", "dwX", startup.dwX);
1577 okChildInt("StartupInfoA", "dwY", startup.dwY);
1578 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1579 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1580 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1581 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1582 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1583 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1584 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1586 /* check child correctly inherited the console */
1587 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1588 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1589 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1590 okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1591 okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1592 okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1593 okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1594 okChildInt("Console", "Attributes", sbi.wAttributes);
1595 okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1596 okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1597 okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1598 okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1599 okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1600 okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1601 okChildInt("Console", "InputCP", cpIn);
1602 okChildInt("Console", "OutputCP", cpOut);
1603 okChildInt("Console", "InputMode", modeIn);
1604 okChildInt("Console", "OutputMode", modeOut);
1606 if (run_tests)
1608 ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1609 ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1611 else
1612 win_skip("Setting the codepage is not implemented\n");
1614 ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1615 ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1616 trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1617 ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1619 release_memory();
1620 DeleteFileA(resfile);
1622 ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1623 ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(),
1624 &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1625 "Duplicating as inheritable child-output pipe\n");
1626 CloseHandle(hChildOut);
1628 ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1629 ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(),
1630 &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1631 "Duplicating as inheritable child-input pipe\n");
1632 CloseHandle(hChildIn);
1634 memset(&startup, 0, sizeof(startup));
1635 startup.cb = sizeof(startup);
1636 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1637 startup.wShowWindow = SW_SHOWNORMAL;
1638 startup.hStdInput = hChildInInh;
1639 startup.hStdOutput = hChildOutInh;
1640 startup.hStdError = hChildOutInh;
1642 get_file_name(resfile);
1643 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile);
1644 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1645 ok(CloseHandle(hChildInInh), "Closing handle\n");
1646 ok(CloseHandle(hChildOutInh), "Closing handle\n");
1648 msg_len = strlen(msg) + 1;
1649 ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1650 ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1651 memset(buffer, 0, sizeof(buffer));
1652 ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1653 ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1655 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1656 ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1658 /* wait for child to terminate */
1659 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1660 /* child process has changed result file, so let profile functions know about it */
1661 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1663 okChildString("StdHandle", "msg", msg);
1665 release_memory();
1666 DeleteFileA(resfile);
1669 static void test_ExitCode(void)
1671 char buffer[MAX_PATH];
1672 PROCESS_INFORMATION info;
1673 STARTUPINFOA startup;
1674 DWORD code;
1676 /* let's start simplistic */
1677 memset(&startup, 0, sizeof(startup));
1678 startup.cb = sizeof(startup);
1679 startup.dwFlags = STARTF_USESHOWWINDOW;
1680 startup.wShowWindow = SW_SHOWNORMAL;
1682 get_file_name(resfile);
1683 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile);
1684 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1686 /* wait for child to terminate */
1687 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1688 /* child process has changed result file, so let profile functions know about it */
1689 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1691 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1692 okChildInt("ExitCode", "value", code);
1694 release_memory();
1695 DeleteFileA(resfile);
1698 static void test_OpenProcess(void)
1700 HANDLE hproc;
1701 void *addr1;
1702 MEMORY_BASIC_INFORMATION info;
1703 SIZE_T dummy, read_bytes;
1704 BOOL ret;
1706 /* not exported in all windows versions */
1707 if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1708 win_skip("VirtualAllocEx not found\n");
1709 return;
1712 /* without PROCESS_VM_OPERATION */
1713 hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1714 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1716 SetLastError(0xdeadbeef);
1717 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1718 ok(!addr1, "VirtualAllocEx should fail\n");
1719 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1720 { /* Win9x */
1721 CloseHandle(hproc);
1722 win_skip("VirtualAllocEx not implemented\n");
1723 return;
1725 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1727 read_bytes = 0xdeadbeef;
1728 SetLastError(0xdeadbeef);
1729 ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes);
1730 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1731 ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1733 CloseHandle(hproc);
1735 hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1736 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1738 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1739 ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1741 /* without PROCESS_QUERY_INFORMATION */
1742 SetLastError(0xdeadbeef);
1743 ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1744 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1745 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1747 /* without PROCESS_VM_READ */
1748 read_bytes = 0xdeadbeef;
1749 SetLastError(0xdeadbeef);
1750 ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1751 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1752 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1753 ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1755 CloseHandle(hproc);
1757 hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1759 memset(&info, 0xcc, sizeof(info));
1760 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1761 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1763 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1764 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1765 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1766 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1767 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1768 /* NT reports Protect == 0 for a not committed memory block */
1769 ok(info.Protect == 0 /* NT */ ||
1770 info.Protect == PAGE_NOACCESS, /* Win9x */
1771 "%x != PAGE_NOACCESS\n", info.Protect);
1772 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1774 SetLastError(0xdeadbeef);
1775 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1776 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1777 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1779 CloseHandle(hproc);
1781 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1782 if (hproc)
1784 SetLastError(0xdeadbeef);
1785 memset(&info, 0xcc, sizeof(info));
1786 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1787 if (read_bytes) /* win8 */
1789 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1790 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1791 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1792 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1793 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1794 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1795 ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
1796 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1798 else /* before win8 */
1799 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1801 SetLastError(0xdeadbeef);
1802 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1803 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1804 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1806 CloseHandle(hproc);
1809 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1812 static void test_GetProcessVersion(void)
1814 static char cmdline[] = "winver.exe";
1815 PROCESS_INFORMATION pi;
1816 STARTUPINFOA si;
1817 DWORD ret;
1819 SetLastError(0xdeadbeef);
1820 ret = GetProcessVersion(0);
1821 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1823 SetLastError(0xdeadbeef);
1824 ret = GetProcessVersion(GetCurrentProcessId());
1825 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1827 memset(&si, 0, sizeof(si));
1828 si.cb = sizeof(si);
1829 si.dwFlags = STARTF_USESHOWWINDOW;
1830 si.wShowWindow = SW_HIDE;
1831 SetLastError(0xdeadbeef);
1832 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1833 ok(ret, "CreateProcess error %u\n", GetLastError());
1835 SetLastError(0xdeadbeef);
1836 ret = GetProcessVersion(pi.dwProcessId);
1837 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1839 SetLastError(0xdeadbeef);
1840 ret = TerminateProcess(pi.hProcess, 0);
1841 ok(ret, "TerminateProcess error %u\n", GetLastError());
1843 CloseHandle(pi.hProcess);
1844 CloseHandle(pi.hThread);
1847 static void test_GetProcessImageFileNameA(void)
1849 DWORD rc;
1850 CHAR process[MAX_PATH];
1851 static const char harddisk[] = "\\Device\\HarddiskVolume";
1853 if (!pK32GetProcessImageFileNameA)
1855 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1856 return;
1859 /* callers must guess the buffer size */
1860 SetLastError(0xdeadbeef);
1861 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1862 ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1863 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError());
1865 *process = '\0';
1866 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1867 expect_eq_d(rc, lstrlenA(process));
1868 if (strncmp(process, harddisk, lstrlenA(harddisk)))
1870 todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1871 return;
1874 if (!pQueryFullProcessImageNameA)
1875 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1876 else
1878 CHAR image[MAX_PATH];
1879 DWORD length;
1881 length = sizeof(image);
1882 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1883 expect_eq_d(length, lstrlenA(image));
1884 ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1888 static void test_QueryFullProcessImageNameA(void)
1890 #define INIT_STR "Just some words"
1891 DWORD length, size;
1892 CHAR buf[MAX_PATH], module[MAX_PATH];
1894 if (!pQueryFullProcessImageNameA)
1896 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1897 return;
1900 *module = '\0';
1901 SetLastError(0); /* old Windows don't reset it on success */
1902 size = GetModuleFileNameA(NULL, module, sizeof(module));
1903 ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError());
1905 /* get the buffer length without \0 terminator */
1906 length = sizeof(buf);
1907 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1908 expect_eq_d(length, lstrlenA(buf));
1909 ok((buf[0] == '\\' && buf[1] == '\\') ||
1910 lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1912 /* when the buffer is too small
1913 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1914 * - the size variable is not modified
1915 * tested with the biggest too small size
1917 size = length;
1918 sprintf(buf,INIT_STR);
1919 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1920 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1921 expect_eq_d(length, size);
1922 expect_eq_s(INIT_STR, buf);
1924 /* retest with smaller buffer size
1926 size = 4;
1927 sprintf(buf,INIT_STR);
1928 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1929 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1930 expect_eq_d(4, size);
1931 expect_eq_s(INIT_STR, buf);
1933 /* this is a difference between the ascii and the unicode version
1934 * the unicode version crashes when the size is big enough to hold
1935 * the result while the ascii version throws an error
1937 size = 1024;
1938 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1939 expect_eq_d(1024, size);
1940 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
1943 static void test_QueryFullProcessImageNameW(void)
1945 HANDLE hSelf;
1946 WCHAR module_name[1024], device[1024];
1947 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
1948 WCHAR buf[1024];
1949 DWORD size, len;
1951 if (!pQueryFullProcessImageNameW)
1953 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1954 return;
1957 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1959 /* GetCurrentProcess pseudo-handle */
1960 size = sizeof(buf) / sizeof(buf[0]);
1961 expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
1962 expect_eq_d(lstrlenW(buf), size);
1963 expect_eq_ws_i(buf, module_name);
1965 hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1966 /* Real handle */
1967 size = sizeof(buf) / sizeof(buf[0]);
1968 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1969 expect_eq_d(lstrlenW(buf), size);
1970 expect_eq_ws_i(buf, module_name);
1972 /* Buffer too small */
1973 size = lstrlenW(module_name)/2;
1974 lstrcpyW(buf, deviceW);
1975 SetLastError(0xdeadbeef);
1976 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1977 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
1978 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1979 expect_eq_ws_i(deviceW, buf); /* buffer not changed */
1981 /* Too small - not space for NUL terminator */
1982 size = lstrlenW(module_name);
1983 SetLastError(0xdeadbeef);
1984 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1985 expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
1986 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1988 /* NULL buffer */
1989 size = 0;
1990 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
1991 expect_eq_d(0, size);
1992 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1994 /* Buffer too small */
1995 size = lstrlenW(module_name)/2;
1996 SetLastError(0xdeadbeef);
1997 lstrcpyW(buf, module_name);
1998 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1999 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2000 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2001 expect_eq_ws_i(module_name, buf); /* buffer not changed */
2004 /* native path */
2005 size = sizeof(buf) / sizeof(buf[0]);
2006 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2007 expect_eq_d(lstrlenW(buf), size);
2008 ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2009 ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2011 module_name[2] = '\0';
2012 *device = '\0';
2013 size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0]));
2014 ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2015 len = lstrlenW(device);
2016 ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2018 if (size >= lstrlenW(buf))
2020 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2022 else
2024 ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2025 buf[len] = '\0';
2026 ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2027 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));
2030 CloseHandle(hSelf);
2033 static void test_Handles(void)
2035 HANDLE handle = GetCurrentProcess();
2036 HANDLE h2, h3;
2037 BOOL ret;
2038 DWORD code;
2040 ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2041 handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2042 "invalid current process handle %p\n", handle );
2043 ret = GetExitCodeProcess( handle, &code );
2044 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2045 #ifdef _WIN64
2046 /* truncated handle */
2047 SetLastError( 0xdeadbeef );
2048 handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2049 ret = GetExitCodeProcess( handle, &code );
2050 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2051 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2052 /* sign-extended handle */
2053 SetLastError( 0xdeadbeef );
2054 handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle);
2055 ret = GetExitCodeProcess( handle, &code );
2056 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2057 /* invalid high-word */
2058 SetLastError( 0xdeadbeef );
2059 handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2060 ret = GetExitCodeProcess( handle, &code );
2061 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2062 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2063 #endif
2065 handle = GetStdHandle( STD_ERROR_HANDLE );
2066 ok( handle != 0, "handle %p\n", handle );
2067 DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &h3,
2068 0, TRUE, DUPLICATE_SAME_ACCESS );
2069 SetStdHandle( STD_ERROR_HANDLE, h3 );
2070 CloseHandle( (HANDLE)STD_ERROR_HANDLE );
2071 h2 = GetStdHandle( STD_ERROR_HANDLE );
2072 ok( h2 == 0 ||
2073 broken( h2 == h3) || /* nt4, w2k */
2074 broken( h2 == INVALID_HANDLE_VALUE), /* win9x */
2075 "wrong handle %p/%p\n", h2, h3 );
2076 SetStdHandle( STD_ERROR_HANDLE, handle );
2079 static void test_IsWow64Process(void)
2081 PROCESS_INFORMATION pi;
2082 STARTUPINFOA si;
2083 DWORD ret;
2084 BOOL is_wow64;
2085 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2086 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2088 if (!pIsWow64Process)
2090 skip("IsWow64Process is not available\n");
2091 return;
2094 memset(&si, 0, sizeof(si));
2095 si.cb = sizeof(si);
2096 si.dwFlags = STARTF_USESHOWWINDOW;
2097 si.wShowWindow = SW_HIDE;
2098 ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2099 if (ret)
2101 trace("Created process %s\n", cmdline_wow64);
2102 is_wow64 = FALSE;
2103 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2104 ok(ret, "IsWow64Process failed.\n");
2105 ok(is_wow64, "is_wow64 returned FALSE.\n");
2107 ret = TerminateProcess(pi.hProcess, 0);
2108 ok(ret, "TerminateProcess error\n");
2110 CloseHandle(pi.hProcess);
2111 CloseHandle(pi.hThread);
2114 memset(&si, 0, sizeof(si));
2115 si.cb = sizeof(si);
2116 si.dwFlags = STARTF_USESHOWWINDOW;
2117 si.wShowWindow = SW_HIDE;
2118 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2119 if (ret)
2121 trace("Created process %s\n", cmdline);
2122 is_wow64 = TRUE;
2123 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2124 ok(ret, "IsWow64Process failed.\n");
2125 ok(!is_wow64, "is_wow64 returned TRUE.\n");
2127 ret = TerminateProcess(pi.hProcess, 0);
2128 ok(ret, "TerminateProcess error\n");
2130 CloseHandle(pi.hProcess);
2131 CloseHandle(pi.hThread);
2135 static void test_SystemInfo(void)
2137 SYSTEM_INFO si, nsi;
2138 BOOL is_wow64;
2140 if (!pGetNativeSystemInfo)
2142 win_skip("GetNativeSystemInfo is not available\n");
2143 return;
2146 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2148 GetSystemInfo(&si);
2149 pGetNativeSystemInfo(&nsi);
2150 if (is_wow64)
2152 if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2154 ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2155 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2156 S(U(nsi)).wProcessorArchitecture);
2157 ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664,
2158 "Expected PROCESSOR_AMD_X8664, got %d\n",
2159 nsi.dwProcessorType);
2162 else
2164 ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2165 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2166 S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2167 ok(si.dwProcessorType == nsi.dwProcessorType,
2168 "Expected no difference for dwProcessorType, got %d and %d\n",
2169 si.dwProcessorType, nsi.dwProcessorType);
2173 static void test_RegistryQuota(void)
2175 BOOL ret;
2176 DWORD max_quota, used_quota;
2178 if (!pGetSystemRegistryQuota)
2180 win_skip("GetSystemRegistryQuota is not available\n");
2181 return;
2184 ret = pGetSystemRegistryQuota(NULL, NULL);
2185 ok(ret == TRUE,
2186 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2188 ret = pGetSystemRegistryQuota(&max_quota, NULL);
2189 ok(ret == TRUE,
2190 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2192 ret = pGetSystemRegistryQuota(NULL, &used_quota);
2193 ok(ret == TRUE,
2194 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2196 ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2197 ok(ret == TRUE,
2198 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2201 static void test_TerminateProcess(void)
2203 static char cmdline[] = "winver.exe";
2204 PROCESS_INFORMATION pi;
2205 STARTUPINFOA si;
2206 DWORD ret;
2207 HANDLE dummy, thread;
2209 memset(&si, 0, sizeof(si));
2210 si.cb = sizeof(si);
2211 SetLastError(0xdeadbeef);
2212 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2213 ok(ret, "CreateProcess error %u\n", GetLastError());
2215 SetLastError(0xdeadbeef);
2216 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2217 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2219 /* create a not closed thread handle duplicate in the target process */
2220 SetLastError(0xdeadbeef);
2221 ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy,
2222 0, FALSE, DUPLICATE_SAME_ACCESS);
2223 ok(ret, "DuplicateHandle error %u\n", GetLastError());
2225 SetLastError(0xdeadbeef);
2226 ret = TerminateThread(thread, 0);
2227 ok(ret, "TerminateThread error %u\n", GetLastError());
2228 CloseHandle(thread);
2230 SetLastError(0xdeadbeef);
2231 ret = TerminateProcess(pi.hProcess, 0);
2232 ok(ret, "TerminateProcess error %u\n", GetLastError());
2234 CloseHandle(pi.hProcess);
2235 CloseHandle(pi.hThread);
2238 static void test_DuplicateHandle(void)
2240 char path[MAX_PATH], file_name[MAX_PATH];
2241 HANDLE f, fmin, out;
2242 DWORD info;
2243 BOOL r;
2245 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2246 GetCurrentProcess(), &out, 0, FALSE,
2247 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2248 ok(r, "DuplicateHandle error %u\n", GetLastError());
2249 r = GetHandleInformation(out, &info);
2250 ok(r, "GetHandleInformation error %u\n", GetLastError());
2251 ok(info == 0, "info = %x\n", info);
2252 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2253 CloseHandle(out);
2255 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2256 GetCurrentProcess(), &out, 0, TRUE,
2257 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2258 ok(r, "DuplicateHandle error %u\n", GetLastError());
2259 r = GetHandleInformation(out, &info);
2260 ok(r, "GetHandleInformation error %u\n", GetLastError());
2261 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2262 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2263 CloseHandle(out);
2265 GetTempPathA(MAX_PATH, path);
2266 GetTempFileNameA(path, "wt", 0, file_name);
2267 f = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2268 if (f == INVALID_HANDLE_VALUE)
2270 ok(0, "could not create %s\n", file_name);
2271 return;
2274 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2275 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2276 ok(r, "DuplicateHandle error %u\n", GetLastError());
2277 ok(f == out, "f != out\n");
2278 r = GetHandleInformation(out, &info);
2279 ok(r, "GetHandleInformation error %u\n", GetLastError());
2280 ok(info == 0, "info = %x\n", info);
2282 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2283 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2284 ok(r, "DuplicateHandle error %u\n", GetLastError());
2285 ok(f == out, "f != out\n");
2286 r = GetHandleInformation(out, &info);
2287 ok(r, "GetHandleInformation error %u\n", GetLastError());
2288 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2290 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
2291 ok(r, "SetHandleInformation error %u\n", GetLastError());
2292 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2293 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2294 ok(r, "DuplicateHandle error %u\n", GetLastError());
2295 ok(f != out, "f == out\n");
2296 r = GetHandleInformation(out, &info);
2297 ok(r, "GetHandleInformation error %u\n", GetLastError());
2298 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2299 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2300 ok(r, "SetHandleInformation error %u\n", GetLastError());
2302 /* Test if DuplicateHandle allocates first free handle */
2303 if (f > out)
2305 fmin = out;
2307 else
2309 fmin = f;
2310 f = out;
2312 CloseHandle(fmin);
2313 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2314 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2315 ok(r, "DuplicateHandle error %u\n", GetLastError());
2316 ok(f == out, "f != out\n");
2317 CloseHandle(out);
2318 DeleteFileA(file_name);
2320 f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2321 if (!is_console(f))
2323 skip("DuplicateHandle on console handle\n");
2324 CloseHandle(f);
2325 return;
2328 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2329 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2330 ok(r, "DuplicateHandle error %u\n", GetLastError());
2331 todo_wine ok(f != out, "f == out\n");
2332 CloseHandle(out);
2335 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2336 static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2338 LPOVERLAPPED overlapped;
2339 ULONG_PTR value;
2340 DWORD key;
2341 BOOL ret;
2343 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait);
2345 ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
2346 if (ret)
2348 ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key);
2349 ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2350 ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2354 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2355 static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2357 BOOL ret;
2358 char buffer[MAX_PATH];
2359 STARTUPINFOA si = {0};
2361 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command);
2363 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2364 ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError());
2368 static void test_IsProcessInJob(void)
2370 HANDLE job, job2;
2371 PROCESS_INFORMATION pi;
2372 BOOL ret, out;
2373 DWORD dwret;
2375 if (!pIsProcessInJob)
2377 win_skip("IsProcessInJob not available.\n");
2378 return;
2381 job = pCreateJobObjectW(NULL, NULL);
2382 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2384 job2 = pCreateJobObjectW(NULL, NULL);
2385 ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError());
2387 create_process("wait", &pi);
2389 out = TRUE;
2390 ret = pIsProcessInJob(pi.hProcess, job, &out);
2391 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2392 ok(!out, "IsProcessInJob returned out=%u\n", out);
2394 out = TRUE;
2395 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2396 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2397 ok(!out, "IsProcessInJob returned out=%u\n", out);
2399 out = TRUE;
2400 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2401 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2402 ok(!out, "IsProcessInJob returned out=%u\n", out);
2404 ret = pAssignProcessToJobObject(job, pi.hProcess);
2405 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2407 out = FALSE;
2408 ret = pIsProcessInJob(pi.hProcess, job, &out);
2409 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2410 ok(out, "IsProcessInJob returned out=%u\n", out);
2412 out = TRUE;
2413 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2414 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2415 ok(!out, "IsProcessInJob returned out=%u\n", out);
2417 out = FALSE;
2418 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2419 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2420 ok(out, "IsProcessInJob returned out=%u\n", out);
2422 TerminateProcess(pi.hProcess, 0);
2424 dwret = WaitForSingleObject(pi.hProcess, 1000);
2425 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2427 out = FALSE;
2428 ret = pIsProcessInJob(pi.hProcess, job, &out);
2429 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2430 ok(out, "IsProcessInJob returned out=%u\n", out);
2432 CloseHandle(pi.hProcess);
2433 CloseHandle(pi.hThread);
2434 CloseHandle(job);
2435 CloseHandle(job2);
2438 static void test_TerminateJobObject(void)
2440 HANDLE job;
2441 PROCESS_INFORMATION pi;
2442 BOOL ret;
2443 DWORD dwret;
2445 job = pCreateJobObjectW(NULL, NULL);
2446 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2448 create_process("wait", &pi);
2450 ret = pAssignProcessToJobObject(job, pi.hProcess);
2451 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2453 ret = pTerminateJobObject(job, 123);
2454 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2456 dwret = WaitForSingleObject(pi.hProcess, 1000);
2457 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2458 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2460 ret = GetExitCodeProcess(pi.hProcess, &dwret);
2461 ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
2462 ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
2463 "wrong exitcode %u\n", dwret);
2465 CloseHandle(pi.hProcess);
2466 CloseHandle(pi.hThread);
2468 /* Test adding an already terminated process to a job object */
2469 create_process("exit", &pi);
2471 dwret = WaitForSingleObject(pi.hProcess, 1000);
2472 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2474 SetLastError(0xdeadbeef);
2475 ret = pAssignProcessToJobObject(job, pi.hProcess);
2476 ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2477 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2479 CloseHandle(pi.hProcess);
2480 CloseHandle(pi.hThread);
2482 CloseHandle(job);
2485 static void test_QueryInformationJobObject(void)
2487 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2488 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2489 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2490 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2491 DWORD dwret, ret_len;
2492 PROCESS_INFORMATION pi[2];
2493 HANDLE job;
2494 BOOL ret;
2496 job = pCreateJobObjectW(NULL, NULL);
2497 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2499 /* Only active processes are returned */
2500 create_process("exit", &pi[0]);
2501 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2502 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2503 dwret = WaitForSingleObject(pi[0].hProcess, 1000);
2504 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2506 CloseHandle(pi[0].hProcess);
2507 CloseHandle(pi[0].hThread);
2509 create_process("wait", &pi[0]);
2510 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2511 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2513 create_process("wait", &pi[1]);
2514 ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2515 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2517 SetLastError(0xdeadbeef);
2518 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2519 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len);
2520 ok(!ret, "QueryInformationJobObject expected failure\n");
2521 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2523 SetLastError(0xdeadbeef);
2524 memset(buf, 0, sizeof(buf));
2525 pid_list->NumberOfAssignedProcesses = 42;
2526 pid_list->NumberOfProcessIdsInList = 42;
2527 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2528 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len);
2529 todo_wine
2530 ok(!ret, "QueryInformationJobObject expected failure\n");
2531 todo_wine
2532 expect_eq_d(ERROR_MORE_DATA, GetLastError());
2533 if (ret)
2535 todo_wine
2536 expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2537 todo_wine
2538 expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2541 memset(buf, 0, sizeof(buf));
2542 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2543 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2544 if(ret)
2546 if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2547 win_skip("Number of assigned processes broken on Win 8\n");
2548 else
2550 ULONG_PTR *list = pid_list->ProcessIdList;
2552 todo_wine
2553 ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]),
2554 "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2556 todo_wine
2557 expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2558 todo_wine
2559 expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2560 todo_wine
2561 expect_eq_d(pi[0].dwProcessId, list[0]);
2562 todo_wine
2563 expect_eq_d(pi[1].dwProcessId, list[1]);
2567 /* test JobObjectBasicLimitInformation */
2568 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2569 sizeof(*basic_limit_info) - 1, &ret_len);
2570 ok(!ret, "QueryInformationJobObject expected failure\n");
2571 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2573 ret_len = 0xdeadbeef;
2574 memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2575 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2576 sizeof(*basic_limit_info), &ret_len);
2577 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2578 ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2579 expect_eq_d(0, basic_limit_info->LimitFlags);
2581 /* test JobObjectExtendedLimitInformation */
2582 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2583 sizeof(ext_limit_info) - 1, &ret_len);
2584 ok(!ret, "QueryInformationJobObject expected failure\n");
2585 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2587 ret_len = 0xdeadbeef;
2588 memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2589 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2590 sizeof(ext_limit_info), &ret_len);
2591 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2592 ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2593 expect_eq_d(0, basic_limit_info->LimitFlags);
2595 TerminateProcess(pi[0].hProcess, 0);
2596 CloseHandle(pi[0].hProcess);
2597 CloseHandle(pi[0].hThread);
2599 TerminateProcess(pi[1].hProcess, 0);
2600 CloseHandle(pi[1].hProcess);
2601 CloseHandle(pi[1].hThread);
2603 CloseHandle(job);
2606 static void test_CompletionPort(void)
2608 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
2609 PROCESS_INFORMATION pi;
2610 HANDLE job, port;
2611 DWORD dwret;
2612 BOOL ret;
2614 job = pCreateJobObjectW(NULL, NULL);
2615 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2617 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2618 ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
2620 port_info.CompletionKey = job;
2621 port_info.CompletionPort = port;
2622 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2623 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2625 create_process("wait", &pi);
2627 ret = pAssignProcessToJobObject(job, pi.hProcess);
2628 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2630 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2632 TerminateProcess(pi.hProcess, 0);
2633 dwret = WaitForSingleObject(pi.hProcess, 1000);
2634 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2636 test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2637 test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100);
2639 CloseHandle(pi.hProcess);
2640 CloseHandle(pi.hThread);
2641 CloseHandle(job);
2642 CloseHandle(port);
2645 static void test_KillOnJobClose(void)
2647 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2648 PROCESS_INFORMATION pi;
2649 DWORD dwret;
2650 HANDLE job;
2651 BOOL ret;
2653 job = pCreateJobObjectW(NULL, NULL);
2654 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2656 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
2657 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2658 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2660 win_skip("Kill on job close limit not available\n");
2661 return;
2663 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2665 create_process("wait", &pi);
2667 ret = pAssignProcessToJobObject(job, pi.hProcess);
2668 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2670 CloseHandle(job);
2672 dwret = WaitForSingleObject(pi.hProcess, 1000);
2673 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2674 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2676 CloseHandle(pi.hProcess);
2677 CloseHandle(pi.hThread);
2680 static void test_WaitForJobObject(void)
2682 HANDLE job;
2683 PROCESS_INFORMATION pi;
2684 BOOL ret;
2685 DWORD dwret;
2687 /* test waiting for a job object when the process is killed */
2688 job = pCreateJobObjectW(NULL, NULL);
2689 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2691 dwret = WaitForSingleObject(job, 100);
2692 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2694 create_process("wait", &pi);
2696 ret = pAssignProcessToJobObject(job, pi.hProcess);
2697 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2699 dwret = WaitForSingleObject(job, 100);
2700 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2702 ret = pTerminateJobObject(job, 123);
2703 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2705 dwret = WaitForSingleObject(job, 500);
2706 ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2707 "WaitForSingleObject returned %u\n", dwret);
2709 if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2711 CloseHandle(pi.hProcess);
2712 CloseHandle(pi.hThread);
2713 CloseHandle(job);
2714 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2715 return;
2718 /* the object is not reset immediately */
2719 dwret = WaitForSingleObject(job, 100);
2720 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2722 CloseHandle(pi.hProcess);
2723 CloseHandle(pi.hThread);
2725 /* creating a new process doesn't reset the signalled state */
2726 create_process("wait", &pi);
2728 ret = pAssignProcessToJobObject(job, pi.hProcess);
2729 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2731 dwret = WaitForSingleObject(job, 100);
2732 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2734 ret = pTerminateJobObject(job, 123);
2735 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2737 CloseHandle(pi.hProcess);
2738 CloseHandle(pi.hThread);
2740 CloseHandle(job);
2742 /* repeat the test, but this time the process terminates properly */
2743 job = pCreateJobObjectW(NULL, NULL);
2744 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2746 dwret = WaitForSingleObject(job, 100);
2747 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2749 create_process("exit", &pi);
2751 ret = pAssignProcessToJobObject(job, pi.hProcess);
2752 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2754 dwret = WaitForSingleObject(job, 100);
2755 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2757 CloseHandle(pi.hProcess);
2758 CloseHandle(pi.hThread);
2759 CloseHandle(job);
2762 static HANDLE test_AddSelfToJob(void)
2764 HANDLE job;
2765 BOOL ret;
2767 job = pCreateJobObjectW(NULL, NULL);
2768 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2770 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2771 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2773 return job;
2776 static void test_jobInheritance(HANDLE job)
2778 char buffer[MAX_PATH];
2779 PROCESS_INFORMATION pi;
2780 STARTUPINFOA si = {0};
2781 DWORD dwret;
2782 BOOL ret, out;
2784 if (!pIsProcessInJob)
2786 win_skip("IsProcessInJob not available.\n");
2787 return;
2790 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2792 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2793 ok(ret, "CreateProcessA error %u\n", GetLastError());
2795 out = FALSE;
2796 ret = pIsProcessInJob(pi.hProcess, job, &out);
2797 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2798 ok(out, "IsProcessInJob returned out=%u\n", out);
2800 dwret = WaitForSingleObject(pi.hProcess, 1000);
2801 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2803 CloseHandle(pi.hProcess);
2804 CloseHandle(pi.hThread);
2807 static void test_BreakawayOk(HANDLE job)
2809 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2810 PROCESS_INFORMATION pi;
2811 STARTUPINFOA si = {0};
2812 char buffer[MAX_PATH];
2813 BOOL ret, out;
2814 DWORD dwret;
2816 if (!pIsProcessInJob)
2818 win_skip("IsProcessInJob not available.\n");
2819 return;
2822 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2824 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2825 ok(!ret, "CreateProcessA expected failure\n");
2826 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2828 if (ret)
2830 TerminateProcess(pi.hProcess, 0);
2832 dwret = WaitForSingleObject(pi.hProcess, 1000);
2833 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2835 CloseHandle(pi.hProcess);
2836 CloseHandle(pi.hThread);
2839 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
2840 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2841 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2843 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2844 ok(ret, "CreateProcessA error %u\n", GetLastError());
2846 ret = pIsProcessInJob(pi.hProcess, job, &out);
2847 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2848 ok(!out, "IsProcessInJob returned out=%u\n", out);
2850 dwret = WaitForSingleObject(pi.hProcess, 1000);
2851 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2853 CloseHandle(pi.hProcess);
2854 CloseHandle(pi.hThread);
2856 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
2857 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2858 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2860 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2861 ok(ret, "CreateProcess error %u\n", GetLastError());
2863 ret = pIsProcessInJob(pi.hProcess, job, &out);
2864 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2865 ok(!out, "IsProcessInJob returned out=%u\n", out);
2867 dwret = WaitForSingleObject(pi.hProcess, 1000);
2868 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2870 CloseHandle(pi.hProcess);
2871 CloseHandle(pi.hThread);
2873 /* unset breakaway ok */
2874 limit_info.BasicLimitInformation.LimitFlags = 0;
2875 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2876 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2879 static void test_StartupNoConsole(void)
2881 #ifndef _WIN64
2882 char buffer[MAX_PATH];
2883 STARTUPINFOA startup;
2884 PROCESS_INFORMATION info;
2886 memset(&startup, 0, sizeof(startup));
2887 startup.cb = sizeof(startup);
2888 startup.dwFlags = STARTF_USESHOWWINDOW;
2889 startup.wShowWindow = SW_SHOWNORMAL;
2890 get_file_name(resfile);
2891 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
2892 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
2893 &info), "CreateProcess\n");
2894 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
2895 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
2896 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
2897 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
2898 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
2899 okChildInt("TEB", "hStdInput", 0);
2900 okChildInt("TEB", "hStdOutput", 0);
2901 okChildInt("TEB", "hStdError", 0);
2902 release_memory();
2903 DeleteFileA(resfile);
2904 #endif
2907 static void test_DetachConsoleHandles(void)
2909 #ifndef _WIN64
2910 char buffer[MAX_PATH];
2911 STARTUPINFOA startup;
2912 PROCESS_INFORMATION info;
2913 UINT result;
2915 memset(&startup, 0, sizeof(startup));
2916 startup.cb = sizeof(startup);
2917 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
2918 startup.wShowWindow = SW_SHOWNORMAL;
2919 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
2920 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
2921 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2922 get_file_name(resfile);
2923 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
2924 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
2925 &info), "CreateProcess\n");
2926 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
2927 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
2929 result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile);
2930 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2931 result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile);
2932 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2933 result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile);
2934 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2935 result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile);
2936 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2937 result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile);
2938 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2939 result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile);
2940 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2942 release_memory();
2943 DeleteFileA(resfile);
2944 #endif
2947 #if defined(__i386__) || defined(__x86_64__)
2948 static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi,
2949 IMAGE_NT_HEADERS *nt_header)
2951 IMAGE_DOS_HEADER dos_header;
2953 if (!ReadProcessMemory(process_handle, mbi->BaseAddress, &dos_header, sizeof(dos_header), NULL))
2954 return FALSE;
2956 if ((dos_header.e_magic != IMAGE_DOS_SIGNATURE) ||
2957 ((ULONG)dos_header.e_lfanew > mbi->RegionSize) ||
2958 (dos_header.e_lfanew < sizeof(dos_header)))
2959 return FALSE;
2961 if (!ReadProcessMemory(process_handle, (char *)mbi->BaseAddress + dos_header.e_lfanew,
2962 nt_header, sizeof(*nt_header), NULL))
2963 return FALSE;
2965 return (nt_header->Signature == IMAGE_NT_SIGNATURE);
2968 static void test_SuspendProcessState(void)
2970 struct pipe_params
2972 ULONG pipe_write_buf;
2973 ULONG pipe_read_buf;
2974 ULONG bytes_returned;
2975 CHAR pipe_name[MAX_PATH];
2978 #ifdef __x86_64__
2979 struct remote_rop_chain
2981 void *exit_process_ptr;
2982 ULONG_PTR home_rcx;
2983 ULONG_PTR home_rdx;
2984 ULONG_PTR home_r8;
2985 ULONG_PTR home_r9;
2986 ULONG_PTR pipe_read_buf_size;
2987 ULONG_PTR bytes_returned;
2988 ULONG_PTR timeout;
2990 #else
2991 struct remote_rop_chain
2993 void *exit_process_ptr;
2994 ULONG_PTR pipe_name;
2995 ULONG_PTR pipe_write_buf;
2996 ULONG_PTR pipe_write_buf_size;
2997 ULONG_PTR pipe_read_buf;
2998 ULONG_PTR pipe_read_buf_size;
2999 ULONG_PTR bytes_returned;
3000 ULONG_PTR timeout;
3001 void *unreached_ret;
3002 ULONG_PTR exit_code;
3004 #endif
3006 static const char pipe_name[] = "\\\\.\\pipe\\TestPipe";
3007 static const ULONG pipe_write_magic = 0x454e4957;
3008 STARTUPINFOA si = {0};
3009 PROCESS_INFORMATION pi = {0};
3010 PVOID exe_base, address, remote_pipe_params, exit_process_ptr,
3011 call_named_pipe_a;
3012 IMAGE_NT_HEADERS nt_header;
3013 MEMORY_BASIC_INFORMATION mbi;
3014 IMAGE_IMPORT_DESCRIPTOR iid;
3015 ULONG_PTR orig_iat_entry_value, iat_entry_value;
3016 struct pipe_params pipe_params;
3017 struct remote_rop_chain rop_chain;
3018 CONTEXT ctx;
3019 HANDLE server_pipe_handle;
3020 BOOL pipe_connected;
3021 ULONG pipe_magic, numb;
3022 BOOL ret;
3023 void *entry_ptr, *peb_ptr;
3024 PEB child_peb;
3026 exit_process_ptr = GetProcAddress(hkernel32, "ExitProcess");
3027 ok(exit_process_ptr != NULL, "GetProcAddress ExitProcess failed\n");
3029 call_named_pipe_a = GetProcAddress(hkernel32, "CallNamedPipeA");
3030 ok(call_named_pipe_a != NULL, "GetProcAddress CallNamedPipeA failed\n");
3032 si.cb = sizeof(si);
3033 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3034 ok(ret, "Failed to create process (%d)\n", GetLastError());
3036 /* Find the EXE base in the new process */
3037 exe_base = NULL;
3038 for (address = NULL ;
3039 VirtualQueryEx(pi.hProcess, address, &mbi, sizeof(mbi)) ;
3040 address = (char *)mbi.BaseAddress + mbi.RegionSize) {
3041 if ((mbi.Type == SEC_IMAGE) &&
3042 read_nt_header(pi.hProcess, &mbi, &nt_header) &&
3043 !(nt_header.FileHeader.Characteristics & IMAGE_FILE_DLL)) {
3044 exe_base = mbi.BaseAddress;
3045 break;
3049 /* Make sure we found the EXE in the new process */
3050 ok(exe_base != NULL, "Could not find EXE in remote process\n");
3052 /* Check the EXE has import table */
3053 ok(nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, "Import table VA is zero\n");
3054 ok(nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, "Import table Size is zero\n");
3056 /* Read the first IID */
3057 ret = ReadProcessMemory(pi.hProcess,
3058 (char *)exe_base + nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
3059 &iid, sizeof(iid), NULL);
3060 ok(ret, "Failed to read process EXE IID (%d)\n", GetLastError());
3062 /* Validate the IID is present and not a bound import, and that we have
3063 an OriginalFirstThunk to compare with */
3064 ok(iid.Name, "Exe first IID does not have a Name\n");
3065 ok(iid.FirstThunk, "Exe first IID does not have a FirstThunk\n");
3066 ok(!iid.TimeDateStamp, "Exe first IID is a bound import (UNSUPPORTED for current test)\n");
3067 ok(iid.OriginalFirstThunk, "Exe first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3069 /* Read a single IAT entry from the FirstThunk */
3070 ret = ReadProcessMemory(pi.hProcess, (char *)exe_base + iid.FirstThunk,
3071 &iat_entry_value, sizeof(iat_entry_value), NULL);
3072 ok(ret, "Failed to read IAT entry from FirstThunk (%d)\n", GetLastError());
3073 ok(iat_entry_value, "IAT entry in FirstThunk is NULL\n");
3075 /* Read a single IAT entry from the OriginalFirstThunk */
3076 ret = ReadProcessMemory(pi.hProcess, (char *)exe_base + iid.OriginalFirstThunk,
3077 &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL);
3078 ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%d)\n", GetLastError());
3079 ok(orig_iat_entry_value, "IAT entry in OriginalFirstThunk is NULL\n");
3081 /* The IAT should be UNRESOLVED */
3082 todo_wine
3083 ok(iat_entry_value == orig_iat_entry_value, "IAT entry resolved prematurely\n");
3085 server_pipe_handle = CreateNamedPipeA(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH,
3086 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0x20000, 0x20000,
3087 0, NULL);
3088 ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%d)\n", GetLastError());
3090 /* Setup the remote process enviornment */
3091 ctx.ContextFlags = CONTEXT_FULL;
3092 ret = GetThreadContext(pi.hThread, &ctx);
3093 ok(ret, "Failed retrieving remote thread context (%d)\n", GetLastError());
3095 remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE);
3096 ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%d)\n", GetLastError());
3098 pipe_params.pipe_write_buf = pipe_write_magic;
3099 pipe_params.pipe_read_buf = 0;
3100 pipe_params.bytes_returned = 0;
3101 strcpy(pipe_params.pipe_name, pipe_name);
3103 ret = WriteProcessMemory(pi.hProcess, remote_pipe_params,
3104 &pipe_params, sizeof(pipe_params), NULL);
3105 ok(ret, "Failed to write to remote process memory (%d)\n", GetLastError());
3107 #ifdef __x86_64__
3108 ok( ctx.ContextFlags == CONTEXT_FULL, "wrong flags %x\n", ctx.ContextFlags );
3109 ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax );
3110 todo_wine
3112 ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx );
3113 ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi );
3114 ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi );
3115 ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp );
3116 ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp );
3118 entry_ptr = (void *)ctx.Rcx;
3119 peb_ptr = (void *)ctx.Rdx;
3121 rop_chain.exit_process_ptr = exit_process_ptr;
3122 ctx.Rcx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3123 ctx.Rdx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3124 ctx.R8 = sizeof(pipe_params.pipe_write_buf);
3125 ctx.R9 = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3126 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3127 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3128 rop_chain.timeout = 10000;
3130 ctx.Rip = (ULONG_PTR)call_named_pipe_a;
3131 ctx.Rsp -= sizeof(rop_chain);
3132 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL);
3133 ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3134 #else
3135 ok( ctx.ContextFlags == CONTEXT_FULL, "wrong flags %x\n", ctx.ContextFlags );
3136 todo_wine
3137 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp );
3138 if (!ctx.Ebp) /* winxp is completely different */
3140 ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx );
3141 ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx );
3142 ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi );
3143 ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi );
3144 ok( !((ctx.Esp + 0x10) & 0xfff), "esp is not at top of stack page %08x\n", ctx.Esp );
3146 entry_ptr = (void *)ctx.Eax;
3147 peb_ptr = (void *)ctx.Ebx;
3149 rop_chain.exit_process_ptr = exit_process_ptr;
3150 rop_chain.pipe_name = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3151 rop_chain.pipe_write_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3152 rop_chain.pipe_write_buf_size = sizeof(pipe_params.pipe_write_buf);
3153 rop_chain.pipe_read_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3154 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3155 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3156 rop_chain.timeout = 10000;
3157 rop_chain.exit_code = 0;
3159 ctx.Eip = (ULONG_PTR)call_named_pipe_a;
3160 ctx.Esp -= sizeof(rop_chain);
3161 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Esp, &rop_chain, sizeof(rop_chain), NULL);
3162 ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3163 #endif
3165 ret = ReadProcessMemory( pi.hProcess, peb_ptr, &child_peb, sizeof(child_peb), NULL );
3166 todo_wine
3167 ok( ret, "Failed to read PEB (%u)\n", GetLastError() );
3168 if (ret)
3169 ok( child_peb.ImageBaseAddress == exe_base, "wrong base %p/%p\n",
3170 child_peb.ImageBaseAddress, exe_base );
3171 todo_wine
3172 ok( entry_ptr == (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint,
3173 "wrong entry point %p/%p\n", entry_ptr,
3174 (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint );
3176 ret = SetThreadContext(pi.hThread, &ctx);
3177 ok(ret, "Failed to set remote thread context (%d)\n", GetLastError());
3179 ResumeThread(pi.hThread);
3181 pipe_connected = ConnectNamedPipe(server_pipe_handle, NULL) || (GetLastError() == ERROR_PIPE_CONNECTED);
3182 ok(pipe_connected, "Pipe did not connect\n");
3184 ret = ReadFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3185 ok(ret, "Failed to read buffer from pipe (%d)\n", GetLastError());
3187 ok(pipe_magic == pipe_write_magic, "Did not get the correct magic from the remote process\n");
3189 /* Validate the Imports, at this point the thread in the new process should have
3190 initialized the EXE module imports and call each dll DllMain notifying it on
3191 the new thread in the process. */
3192 iat_entry_value = orig_iat_entry_value = 0;
3194 /* Read a single IAT entry from the FirstThunk */
3195 ret = ReadProcessMemory(pi.hProcess, (char *)exe_base + iid.FirstThunk,
3196 &iat_entry_value, sizeof(iat_entry_value), NULL);
3197 ok(ret, "Failed to read IAT entry from FirstThunk [2] (%d)\n", GetLastError());
3199 /* Read a single IAT entry from the OriginalFirstThunk */
3200 ret = ReadProcessMemory(pi.hProcess, (char *)exe_base + iid.OriginalFirstThunk,
3201 &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL);
3202 ok(ret, "Failed to read IAT entry from OriginalFirstThunk [2] (%d)\n", GetLastError());
3204 /* The IAT should be RESOLVED */
3205 ok(iat_entry_value != orig_iat_entry_value, "EXE IAT is not resolved\n");
3207 ret = WriteFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3208 ok(ret, "Failed to write the magic back to the pipe (%d)\n", GetLastError());
3210 CloseHandle(server_pipe_handle);
3211 WaitForSingleObject(pi.hProcess, 10000);
3212 CloseHandle(pi.hProcess);
3213 CloseHandle(pi.hThread);
3215 #else
3216 static void test_SuspendProcessState(void)
3219 #endif
3221 static void test_DetachStdHandles(void)
3223 #ifndef _WIN64
3224 char buffer[MAX_PATH], tempfile[MAX_PATH];
3225 STARTUPINFOA startup;
3226 PROCESS_INFORMATION info;
3227 HANDLE hstdin, hstdout, hstderr, htemp;
3228 BOOL res;
3230 hstdin = GetStdHandle(STD_INPUT_HANDLE);
3231 hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
3232 hstderr = GetStdHandle(STD_ERROR_HANDLE);
3234 get_file_name(tempfile);
3235 htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3236 ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n");
3238 memset(&startup, 0, sizeof(startup));
3239 startup.cb = sizeof(startup);
3240 startup.dwFlags = STARTF_USESHOWWINDOW;
3241 startup.wShowWindow = SW_SHOWNORMAL;
3242 get_file_name(resfile);
3243 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3245 SetStdHandle(STD_INPUT_HANDLE, htemp);
3246 SetStdHandle(STD_OUTPUT_HANDLE, htemp);
3247 SetStdHandle(STD_ERROR_HANDLE, htemp);
3249 res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3250 &info);
3252 SetStdHandle(STD_INPUT_HANDLE, hstdin);
3253 SetStdHandle(STD_OUTPUT_HANDLE, hstdout);
3254 SetStdHandle(STD_ERROR_HANDLE, hstderr);
3256 ok(res, "CreateProcess failed\n");
3257 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3258 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3259 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3260 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3261 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3262 okChildInt("TEB", "hStdInput", 0);
3263 okChildInt("TEB", "hStdOutput", 0);
3264 okChildInt("TEB", "hStdError", 0);
3265 release_memory();
3266 DeleteFileA(resfile);
3268 CloseHandle(htemp);
3269 DeleteFileA(tempfile);
3270 #endif
3273 static void test_GetNumaProcessorNode(void)
3275 SYSTEM_INFO si;
3276 UCHAR node;
3277 BOOL ret;
3278 int i;
3280 if (!pGetNumaProcessorNode)
3282 win_skip("GetNumaProcessorNode is missing\n");
3283 return;
3286 GetSystemInfo(&si);
3287 for (i = 0; i < 256; i++)
3289 SetLastError(0xdeadbeef);
3290 node = (i < si.dwNumberOfProcessors) ? 0xFF : 0xAA;
3291 ret = pGetNumaProcessorNode(i, &node);
3292 if (i < si.dwNumberOfProcessors)
3294 ok(ret, "GetNumaProcessorNode returned FALSE for processor %d\n", i);
3295 ok(node != 0xFF, "expected node != 0xFF, but got 0xFF\n");
3297 else
3299 ok(!ret, "GetNumaProcessorNode returned TRUE for processor %d\n", i);
3300 ok(node == 0xFF || broken(node == 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node);
3301 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3306 static void test_session_info(void)
3308 DWORD session_id, active_session;
3309 BOOL r;
3311 if (!pProcessIdToSessionId)
3313 win_skip("ProcessIdToSessionId is missing\n");
3314 return;
3317 r = pProcessIdToSessionId(GetCurrentProcessId(), &session_id);
3318 ok(r, "ProcessIdToSessionId failed: %u\n", GetLastError());
3319 trace("session_id = %x\n", session_id);
3321 active_session = pWTSGetActiveConsoleSessionId();
3322 trace("active_session = %x\n", active_session);
3325 static void test_process_info(void)
3327 char buf[4096];
3328 static const ULONG info_size[] =
3330 sizeof(PROCESS_BASIC_INFORMATION) /* ProcessBasicInformation */,
3331 sizeof(QUOTA_LIMITS) /* ProcessQuotaLimits */,
3332 sizeof(IO_COUNTERS) /* ProcessIoCounters */,
3333 sizeof(VM_COUNTERS) /* ProcessVmCounters */,
3334 sizeof(KERNEL_USER_TIMES) /* ProcessTimes */,
3335 sizeof(ULONG) /* ProcessBasePriority */,
3336 sizeof(ULONG) /* ProcessRaisePriority */,
3337 sizeof(HANDLE) /* ProcessDebugPort */,
3338 sizeof(HANDLE) /* ProcessExceptionPort */,
3339 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3340 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3341 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3342 sizeof(ULONG) /* ProcessDefaultHardErrorMode */,
3343 0 /* ProcessIoPortHandlers: kernel-mode only */,
3344 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3345 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3346 sizeof(ULONG) /* ProcessUserModeIOPL */,
3347 sizeof(BOOLEAN) /* ProcessEnableAlignmentFaultFixup */,
3348 sizeof(PROCESS_PRIORITY_CLASS) /* ProcessPriorityClass */,
3349 sizeof(ULONG) /* ProcessWx86Information */,
3350 sizeof(ULONG) /* ProcessHandleCount */,
3351 sizeof(ULONG_PTR) /* ProcessAffinityMask */,
3352 sizeof(ULONG) /* ProcessPriorityBoost */,
3353 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3354 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3355 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3356 sizeof(ULONG_PTR) /* ProcessWow64Information */,
3357 sizeof(buf) /* ProcessImageFileName */,
3358 sizeof(ULONG) /* ProcessLUIDDeviceMapsEnabled */,
3359 sizeof(ULONG) /* ProcessBreakOnTermination */,
3360 sizeof(HANDLE) /* ProcessDebugObjectHandle */,
3361 sizeof(ULONG) /* ProcessDebugFlags */,
3362 sizeof(buf) /* ProcessHandleTracing */,
3363 sizeof(ULONG) /* ProcessIoPriority */,
3364 sizeof(ULONG) /* ProcessExecuteFlags */,
3365 #if 0 /* FIXME: Add remaining classes */
3366 ProcessResourceManagement,
3367 sizeof(ULONG) /* ProcessCookie */,
3368 sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */,
3369 sizeof(PROCESS_CYCLE_TIME_INFORMATION) /* ProcessCycleTime */,
3370 sizeof(ULONG) /* ProcessPagePriority */,
3371 40 /* ProcessInstrumentationCallback */,
3372 sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) /* ProcessThreadStackAllocation */,
3373 sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) /* ProcessWorkingSetWatchEx */,
3374 sizeof(buf) /* ProcessImageFileNameWin32 */,
3375 sizeof(HANDLE) /* ProcessImageFileMapping */,
3376 sizeof(PROCESS_AFFINITY_UPDATE_MODE) /* ProcessAffinityUpdateMode */,
3377 sizeof(PROCESS_MEMORY_ALLOCATION_MODE) /* ProcessMemoryAllocationMode */,
3378 sizeof(USHORT[]) /* ProcessGroupInformation */,
3379 sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */,
3380 sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */,
3381 sizeof(PROCESS_WINDOW_INFORMATION) /* ProcessWindowInformation */,
3382 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */,
3383 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */,
3384 sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */,
3385 sizeof(?) /* ProcessHandleCheckingMode */,
3386 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION) /* ProcessKeepAliveCount */,
3387 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION) /* ProcessRevokeFileHandles */,
3388 sizeof(PROCESS_WORKING_SET_CONTROL) /* ProcessWorkingSetControl */,
3389 sizeof(?) /* ProcessHandleTable */,
3390 sizeof(?) /* ProcessCheckStackExtentsMode */,
3391 sizeof(buf) /* ProcessCommandLineInformation */,
3392 sizeof(PS_PROTECTION) /* ProcessProtectionInformation */,
3393 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO) /* ProcessMemoryExhaustion */,
3394 sizeof(PROCESS_FAULT_INFORMATION) /* ProcessFaultInformation */,
3395 sizeof(PROCESS_TELEMETRY_ID_INFORMATION) /* ProcessTelemetryIdInformation */,
3396 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION) /* ProcessCommitReleaseInformation */,
3397 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3398 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3399 0 /* ProcessReserved1Information */,
3400 0 /* ProcessReserved2Information */,
3401 sizeof(?) /* ProcessSubsystemProcess */,
3402 sizeof(PROCESS_JOB_MEMORY_INFO) /* ProcessJobMemoryInformation */,
3403 #endif
3405 HANDLE hproc;
3406 ULONG i, status, ret_len, size;
3408 if (!pNtQueryInformationProcess)
3410 win_skip("NtQueryInformationProcess is not available on this platform\n");
3411 return;
3414 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
3415 if (!hproc)
3417 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
3418 return;
3421 for (i = 0; i < MaxProcessInfoClass; i++)
3423 size = info_size[i];
3424 if (!size) size = sizeof(buf);
3425 ret_len = 0;
3426 status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len);
3427 if (status == STATUS_NOT_IMPLEMENTED) continue;
3428 if (status == STATUS_INVALID_INFO_CLASS) continue;
3429 if (status == STATUS_INFO_LENGTH_MISMATCH) continue;
3431 switch (i)
3433 case ProcessBasicInformation:
3434 case ProcessQuotaLimits:
3435 case ProcessTimes:
3436 case ProcessPriorityClass:
3437 case ProcessPriorityBoost:
3438 case ProcessLUIDDeviceMapsEnabled:
3439 case 33 /* ProcessIoPriority */:
3440 case ProcessIoCounters:
3441 case ProcessVmCounters:
3442 case ProcessWow64Information:
3443 case ProcessDefaultHardErrorMode:
3444 case ProcessHandleCount:
3445 case ProcessImageFileName:
3446 ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3447 break;
3449 case ProcessAffinityMask:
3450 case ProcessBreakOnTermination:
3451 ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */,
3452 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3453 break;
3455 case ProcessDebugObjectHandle:
3456 ok(status == STATUS_ACCESS_DENIED || status == STATUS_PORT_NOT_SET,
3457 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3458 break;
3460 case ProcessExecuteFlags:
3461 case ProcessDebugPort:
3462 case ProcessDebugFlags:
3463 todo_wine
3464 ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3465 break;
3467 default:
3468 ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3469 break;
3473 CloseHandle(hproc);
3476 static void test_GetLogicalProcessorInformationEx(void)
3478 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info;
3479 DWORD len;
3480 BOOL ret;
3482 if (!pGetLogicalProcessorInformationEx)
3484 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3485 return;
3488 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, NULL);
3489 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
3491 len = 0;
3492 ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len);
3493 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3494 ok(len > 0, "got %u\n", len);
3496 len = 0;
3497 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len);
3498 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3499 ok(len > 0, "got %u\n", len);
3501 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
3502 ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len);
3503 ok(ret, "got %d, error %d\n", ret, GetLastError());
3504 ok(info->Size > 0, "got %u\n", info->Size);
3505 HeapFree(GetProcessHeap(), 0, info);
3508 static void test_largepages(void)
3510 SIZE_T size;
3512 if (!pGetLargePageMinimum) {
3513 skip("No GetLargePageMinimum support.\n");
3514 return;
3516 size = pGetLargePageMinimum();
3518 ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size);
3521 struct proc_thread_attr
3523 DWORD_PTR attr;
3524 SIZE_T size;
3525 void *value;
3528 struct _PROC_THREAD_ATTRIBUTE_LIST
3530 DWORD mask; /* bitmask of items in list */
3531 DWORD size; /* max number of items in list */
3532 DWORD count; /* number of items in list */
3533 DWORD pad;
3534 DWORD_PTR unk;
3535 struct proc_thread_attr attrs[10];
3538 static void test_ProcThreadAttributeList(void)
3540 BOOL ret;
3541 SIZE_T size, needed;
3542 int i;
3543 struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list;
3544 HANDLE handles[4];
3546 if (!pInitializeProcThreadAttributeList)
3548 win_skip("No support for ProcThreadAttributeList\n");
3549 return;
3552 for (i = 0; i <= 10; i++)
3554 needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[i]);
3555 ret = pInitializeProcThreadAttributeList(NULL, i, 0, &size);
3556 ok(!ret, "got %d\n", ret);
3557 if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */
3558 break;
3559 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
3560 ok(size == needed, "%d: got %ld expect %ld\n", i, size, needed);
3562 memset(&list, 0xcc, sizeof(list));
3563 ret = pInitializeProcThreadAttributeList(&list, i, 0, &size);
3564 ok(ret, "got %d\n", ret);
3565 ok(list.mask == 0, "%d: got %08x\n", i, list.mask);
3566 ok(list.size == i, "%d: got %08x\n", i, list.size);
3567 ok(list.count == 0, "%d: got %08x\n", i, list.count);
3568 ok(list.unk == 0, "%d: got %08lx\n", i, list.unk);
3571 memset(handles, 0, sizeof(handles));
3572 memset(&expect_list, 0xcc, sizeof(expect_list));
3573 expect_list.mask = 0;
3574 expect_list.size = i - 1;
3575 expect_list.count = 0;
3576 expect_list.unk = 0;
3578 ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3579 ok(!ret, "got %d\n", ret);
3580 ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %d\n", GetLastError());
3582 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL);
3583 ok(!ret, "got %d\n", ret);
3584 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3586 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL);
3587 ok(!ret, "got %d\n", ret);
3588 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3590 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3591 ok(ret, "got %d\n", ret);
3593 expect_list.mask |= 1 << ProcThreadAttributeParentProcess;
3594 expect_list.attrs[0].attr = PROC_THREAD_ATTRIBUTE_PARENT_PROCESS;
3595 expect_list.attrs[0].size = sizeof(handles[0]);
3596 expect_list.attrs[0].value = handles;
3597 expect_list.count++;
3599 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3600 ok(!ret, "got %d\n", ret);
3601 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3603 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL);
3604 ok(!ret, "got %d\n", ret);
3605 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3607 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3608 ok(ret, "got %d\n", ret);
3610 expect_list.mask |= 1 << ProcThreadAttributeHandleList;
3611 expect_list.attrs[1].attr = PROC_THREAD_ATTRIBUTE_HANDLE_LIST;
3612 expect_list.attrs[1].size = sizeof(handles);
3613 expect_list.attrs[1].value = handles;
3614 expect_list.count++;
3616 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3617 ok(!ret, "got %d\n", ret);
3618 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3620 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3621 ok(ret || (!ret && GetLastError() == ERROR_NOT_SUPPORTED), "got %d gle %d\n", ret, GetLastError());
3623 if (ret)
3625 expect_list.mask |= 1 << ProcThreadAttributeIdealProcessor;
3626 expect_list.attrs[2].attr = PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR;
3627 expect_list.attrs[2].size = sizeof(PROCESSOR_NUMBER);
3628 expect_list.attrs[2].value = handles;
3629 expect_list.count++;
3632 ok(!memcmp(&list, &expect_list, size), "mismatch\n");
3634 pDeleteProcThreadAttributeList(&list);
3637 START_TEST(process)
3639 HANDLE job;
3640 BOOL b = init();
3641 ok(b, "Basic init of CreateProcess test\n");
3642 if (!b) return;
3644 if (myARGC >= 3)
3646 if (!strcmp(myARGV[2], "dump") && myARGC >= 4)
3648 doChild(myARGV[3], (myARGC >= 5) ? myARGV[4] : NULL);
3649 return;
3651 else if (!strcmp(myARGV[2], "wait"))
3653 Sleep(30000);
3654 ok(0, "Child process not killed\n");
3655 return;
3657 else if (!strcmp(myARGV[2], "exit"))
3659 Sleep(100);
3660 return;
3662 else if (!strcmp(myARGV[2], "nested") && myARGC >= 4)
3664 char buffer[MAX_PATH];
3665 STARTUPINFOA startup;
3666 PROCESS_INFORMATION info;
3668 memset(&startup, 0, sizeof(startup));
3669 startup.cb = sizeof(startup);
3670 startup.dwFlags = STARTF_USESHOWWINDOW;
3671 startup.wShowWindow = SW_SHOWNORMAL;
3673 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, myARGV[3]);
3674 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n");
3675 CloseHandle(info.hProcess);
3676 CloseHandle(info.hThread);
3677 return;
3680 ok(0, "Unexpected command %s\n", myARGV[2]);
3681 return;
3684 test_process_info();
3685 test_TerminateProcess();
3686 test_Startup();
3687 test_CommandLine();
3688 test_Directory();
3689 test_Toolhelp();
3690 test_Environment();
3691 test_SuspendFlag();
3692 test_DebuggingFlag();
3693 test_Console();
3694 test_ExitCode();
3695 test_OpenProcess();
3696 test_GetProcessVersion();
3697 test_GetProcessImageFileNameA();
3698 test_QueryFullProcessImageNameA();
3699 test_QueryFullProcessImageNameW();
3700 test_Handles();
3701 test_IsWow64Process();
3702 test_SystemInfo();
3703 test_RegistryQuota();
3704 test_DuplicateHandle();
3705 test_StartupNoConsole();
3706 test_DetachConsoleHandles();
3707 test_DetachStdHandles();
3708 test_GetNumaProcessorNode();
3709 test_session_info();
3710 test_GetLogicalProcessorInformationEx();
3711 test_largepages();
3712 test_ProcThreadAttributeList();
3713 test_SuspendProcessState();
3715 /* things that can be tested:
3716 * lookup: check the way program to be executed is searched
3717 * handles: check the handle inheritance stuff (+sec options)
3718 * console: check if console creation parameters work
3721 if (!pCreateJobObjectW)
3723 win_skip("No job object support\n");
3724 return;
3727 test_IsProcessInJob();
3728 test_TerminateJobObject();
3729 test_QueryInformationJobObject();
3730 test_CompletionPort();
3731 test_KillOnJobClose();
3732 test_WaitForJobObject();
3733 job = test_AddSelfToJob();
3734 test_jobInheritance(job);
3735 test_BreakawayOk(job);
3736 CloseHandle(job);