ntdll: Implement ProcessImageFileNameWin32 in NtQueryInformationProcess.
[wine.git] / dlls / kernel32 / tests / process.c
blobb1a453998ca341010cd7b21999925becb4f6dbfc
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);
621 CloseHandle(info.hThread);
622 CloseHandle(info.hProcess);
624 GetStartupInfoA(&si);
625 okChildInt("StartupInfoA", "cb", startup.cb);
626 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
627 okChildInt("StartupInfoA", "dwX", startup.dwX);
628 okChildInt("StartupInfoA", "dwY", startup.dwY);
629 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
630 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
631 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
632 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
633 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
634 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
635 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
636 release_memory();
637 DeleteFileA(resfile);
639 /* not so simplistic now */
640 memset(&startup, 0, sizeof(startup));
641 startup.cb = sizeof(startup);
642 startup.dwFlags = STARTF_USESHOWWINDOW;
643 startup.wShowWindow = SW_SHOWNORMAL;
644 startup.lpTitle = title;
645 startup.lpDesktop = desktop;
646 startup.dwXCountChars = 0x12121212;
647 startup.dwYCountChars = 0x23232323;
648 startup.dwX = 0x34343434;
649 startup.dwY = 0x45454545;
650 startup.dwXSize = 0x56565656;
651 startup.dwYSize = 0x67676767;
652 startup.dwFillAttribute = 0xA55A;
654 get_file_name(resfile);
655 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
656 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
657 /* wait for child to terminate */
658 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
659 /* child process has changed result file, so let profile functions know about it */
660 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
661 CloseHandle(info.hThread);
662 CloseHandle(info.hProcess);
664 okChildInt("StartupInfoA", "cb", startup.cb);
665 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
666 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
667 okChildInt("StartupInfoA", "dwX", startup.dwX);
668 okChildInt("StartupInfoA", "dwY", startup.dwY);
669 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
670 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
671 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
672 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
673 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
674 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
675 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
676 release_memory();
677 DeleteFileA(resfile);
679 /* not so simplistic now */
680 memset(&startup, 0, sizeof(startup));
681 startup.cb = sizeof(startup);
682 startup.dwFlags = STARTF_USESHOWWINDOW;
683 startup.wShowWindow = SW_SHOWNORMAL;
684 startup.lpTitle = title;
685 startup.lpDesktop = NULL;
686 startup.dwXCountChars = 0x12121212;
687 startup.dwYCountChars = 0x23232323;
688 startup.dwX = 0x34343434;
689 startup.dwY = 0x45454545;
690 startup.dwXSize = 0x56565656;
691 startup.dwYSize = 0x67676767;
692 startup.dwFillAttribute = 0xA55A;
694 get_file_name(resfile);
695 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
696 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
697 /* wait for child to terminate */
698 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
699 /* child process has changed result file, so let profile functions know about it */
700 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
701 CloseHandle(info.hThread);
702 CloseHandle(info.hProcess);
704 okChildInt("StartupInfoA", "cb", startup.cb);
705 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
706 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
707 okChildInt("StartupInfoA", "dwX", startup.dwX);
708 okChildInt("StartupInfoA", "dwY", startup.dwY);
709 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
710 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
711 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
712 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
713 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
714 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
715 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
716 release_memory();
717 DeleteFileA(resfile);
719 /* not so simplistic now */
720 memset(&startup, 0, sizeof(startup));
721 startup.cb = sizeof(startup);
722 startup.dwFlags = STARTF_USESHOWWINDOW;
723 startup.wShowWindow = SW_SHOWNORMAL;
724 startup.lpTitle = title;
725 startup.lpDesktop = empty;
726 startup.dwXCountChars = 0x12121212;
727 startup.dwYCountChars = 0x23232323;
728 startup.dwX = 0x34343434;
729 startup.dwY = 0x45454545;
730 startup.dwXSize = 0x56565656;
731 startup.dwYSize = 0x67676767;
732 startup.dwFillAttribute = 0xA55A;
734 get_file_name(resfile);
735 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
736 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
737 /* wait for child to terminate */
738 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
739 /* child process has changed result file, so let profile functions know about it */
740 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
741 CloseHandle(info.hThread);
742 CloseHandle(info.hProcess);
744 okChildInt("StartupInfoA", "cb", startup.cb);
745 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
746 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
747 okChildInt("StartupInfoA", "dwX", startup.dwX);
748 okChildInt("StartupInfoA", "dwY", startup.dwY);
749 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
750 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
751 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
752 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
753 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
754 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
755 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
756 release_memory();
757 DeleteFileA(resfile);
759 /* not so simplistic now */
760 memset(&startup, 0, sizeof(startup));
761 startup.cb = sizeof(startup);
762 startup.dwFlags = STARTF_USESHOWWINDOW;
763 startup.wShowWindow = SW_SHOWNORMAL;
764 startup.lpTitle = NULL;
765 startup.lpDesktop = desktop;
766 startup.dwXCountChars = 0x12121212;
767 startup.dwYCountChars = 0x23232323;
768 startup.dwX = 0x34343434;
769 startup.dwY = 0x45454545;
770 startup.dwXSize = 0x56565656;
771 startup.dwYSize = 0x67676767;
772 startup.dwFillAttribute = 0xA55A;
774 get_file_name(resfile);
775 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
776 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
777 /* wait for child to terminate */
778 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
779 /* child process has changed result file, so let profile functions know about it */
780 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
781 CloseHandle(info.hThread);
782 CloseHandle(info.hProcess);
784 okChildInt("StartupInfoA", "cb", startup.cb);
785 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
786 result = getChildString( "StartupInfoA", "lpTitle" );
787 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
788 "expected '%s' or null, got '%s'\n", selfname, result );
789 okChildInt("StartupInfoA", "dwX", startup.dwX);
790 okChildInt("StartupInfoA", "dwY", startup.dwY);
791 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
792 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
793 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
794 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
795 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
796 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
797 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
798 release_memory();
799 DeleteFileA(resfile);
801 /* not so simplistic now */
802 memset(&startup, 0, sizeof(startup));
803 startup.cb = sizeof(startup);
804 startup.dwFlags = STARTF_USESHOWWINDOW;
805 startup.wShowWindow = SW_SHOWNORMAL;
806 startup.lpTitle = empty;
807 startup.lpDesktop = desktop;
808 startup.dwXCountChars = 0x12121212;
809 startup.dwYCountChars = 0x23232323;
810 startup.dwX = 0x34343434;
811 startup.dwY = 0x45454545;
812 startup.dwXSize = 0x56565656;
813 startup.dwYSize = 0x67676767;
814 startup.dwFillAttribute = 0xA55A;
816 get_file_name(resfile);
817 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
818 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
819 /* wait for child to terminate */
820 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
821 /* child process has changed result file, so let profile functions know about it */
822 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
823 CloseHandle(info.hThread);
824 CloseHandle(info.hProcess);
826 okChildInt("StartupInfoA", "cb", startup.cb);
827 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
828 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
829 okChildInt("StartupInfoA", "dwX", startup.dwX);
830 okChildInt("StartupInfoA", "dwY", startup.dwY);
831 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
832 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
833 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
834 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
835 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
836 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
837 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
838 release_memory();
839 DeleteFileA(resfile);
841 /* not so simplistic now */
842 memset(&startup, 0, sizeof(startup));
843 startup.cb = sizeof(startup);
844 startup.dwFlags = STARTF_USESHOWWINDOW;
845 startup.wShowWindow = SW_SHOWNORMAL;
846 startup.lpTitle = empty;
847 startup.lpDesktop = empty;
848 startup.dwXCountChars = 0x12121212;
849 startup.dwYCountChars = 0x23232323;
850 startup.dwX = 0x34343434;
851 startup.dwY = 0x45454545;
852 startup.dwXSize = 0x56565656;
853 startup.dwYSize = 0x67676767;
854 startup.dwFillAttribute = 0xA55A;
856 get_file_name(resfile);
857 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
858 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
859 /* wait for child to terminate */
860 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
861 /* child process has changed result file, so let profile functions know about it */
862 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
863 CloseHandle(info.hThread);
864 CloseHandle(info.hProcess);
866 okChildInt("StartupInfoA", "cb", startup.cb);
867 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
868 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
869 okChildInt("StartupInfoA", "dwX", startup.dwX);
870 okChildInt("StartupInfoA", "dwY", startup.dwY);
871 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
872 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
873 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
874 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
875 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
876 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
877 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
878 release_memory();
879 DeleteFileA(resfile);
881 /* TODO: test for A/W and W/A and W/W */
884 static void test_CommandLine(void)
886 char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
887 char buffer2[MAX_PATH];
888 PROCESS_INFORMATION info;
889 STARTUPINFOA startup;
890 BOOL ret;
892 memset(&startup, 0, sizeof(startup));
893 startup.cb = sizeof(startup);
894 startup.dwFlags = STARTF_USESHOWWINDOW;
895 startup.wShowWindow = SW_SHOWNORMAL;
897 /* the basics */
898 get_file_name(resfile);
899 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
900 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
901 /* wait for child to terminate */
902 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
903 /* child process has changed result file, so let profile functions know about it */
904 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
905 CloseHandle(info.hThread);
906 CloseHandle(info.hProcess);
908 okChildInt("Arguments", "argcA", 5);
909 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
910 okChildString("Arguments", "argvA5", NULL);
911 okChildString("Arguments", "CommandLineA", buffer);
912 release_memory();
913 DeleteFileA(resfile);
915 memset(&startup, 0, sizeof(startup));
916 startup.cb = sizeof(startup);
917 startup.dwFlags = STARTF_USESHOWWINDOW;
918 startup.wShowWindow = SW_SHOWNORMAL;
920 /* from François */
921 get_file_name(resfile);
922 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
923 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
924 /* wait for child to terminate */
925 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
926 /* child process has changed result file, so let profile functions know about it */
927 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
928 CloseHandle(info.hThread);
929 CloseHandle(info.hProcess);
931 okChildInt("Arguments", "argcA", 7);
932 okChildString("Arguments", "argvA4", "a\"b\\");
933 okChildString("Arguments", "argvA5", "c\"");
934 okChildString("Arguments", "argvA6", "d");
935 okChildString("Arguments", "argvA7", NULL);
936 okChildString("Arguments", "CommandLineA", buffer);
937 release_memory();
938 DeleteFileA(resfile);
940 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
941 get_file_name(resfile);
942 /* Use exename to avoid buffer containing things like 'C:' */
943 sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
944 SetLastError(0xdeadbeef);
945 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
946 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
947 /* wait for child to terminate */
948 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
949 /* child process has changed result file, so let profile functions know about it */
950 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
951 CloseHandle(info.hThread);
952 CloseHandle(info.hProcess);
953 sprintf(buffer, "./%s", exename);
954 okChildString("Arguments", "argvA0", buffer);
955 release_memory();
956 DeleteFileA(resfile);
958 get_file_name(resfile);
959 /* Use exename to avoid buffer containing things like 'C:' */
960 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 CloseHandle(info.hThread);
969 CloseHandle(info.hProcess);
970 sprintf(buffer, ".\\%s", exename);
971 okChildString("Arguments", "argvA0", buffer);
972 release_memory();
973 DeleteFileA(resfile);
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 tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p, exename, resfile);
982 else sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
983 SetLastError(0xdeadbeef);
984 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
985 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
986 /* wait for child to terminate */
987 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
988 /* child process has changed result file, so let profile functions know about it */
989 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
990 CloseHandle(info.hThread);
991 CloseHandle(info.hProcess);
992 if (p) sprintf(buffer, "..%s/%s", p, exename);
993 else sprintf(buffer, "./%s", exename);
994 okChildString("Arguments", "argvA0", buffer);
995 release_memory();
996 DeleteFileA(resfile);
998 /* Using AppName */
999 get_file_name(resfile);
1000 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
1001 assert ( lpFilePart != 0);
1002 *(lpFilePart -1 ) = 0;
1003 p = strrchr(fullpath, '\\');
1004 /* Use exename to avoid buffer containing things like 'C:' */
1005 if (p) sprintf(buffer, "..%s/%s", p, exename);
1006 else sprintf(buffer, "./%s", exename);
1007 sprintf(buffer2, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile);
1008 SetLastError(0xdeadbeef);
1009 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1010 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
1011 /* wait for child to terminate */
1012 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1013 /* child process has changed result file, so let profile functions know about it */
1014 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1015 CloseHandle(info.hThread);
1016 CloseHandle(info.hProcess);
1017 sprintf(buffer, "tests/process.c dump %s", resfile);
1018 okChildString("Arguments", "argvA0", "dummy");
1019 okChildString("Arguments", "CommandLineA", buffer2);
1020 okChildStringWA("Arguments", "CommandLineW", buffer2);
1021 release_memory();
1022 DeleteFileA(resfile);
1024 if (0) /* Test crashes on NT-based Windows. */
1026 /* Test NULL application name and command line parameters. */
1027 SetLastError(0xdeadbeef);
1028 ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1029 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1030 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1031 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1034 buffer[0] = '\0';
1036 /* Test empty application name parameter. */
1037 SetLastError(0xdeadbeef);
1038 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1039 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1040 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1041 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1042 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1043 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1045 buffer2[0] = '\0';
1047 /* Test empty application name and command line parameters. */
1048 SetLastError(0xdeadbeef);
1049 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1050 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1051 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1052 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1053 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1054 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1056 /* Test empty command line parameter. */
1057 SetLastError(0xdeadbeef);
1058 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1059 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1060 ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
1061 GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ ||
1062 GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ ||
1063 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */,
1064 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1066 strcpy(buffer, "doesnotexist.exe");
1067 strcpy(buffer2, "does not exist.exe");
1069 /* Test nonexistent application name. */
1070 SetLastError(0xdeadbeef);
1071 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1072 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1073 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1075 SetLastError(0xdeadbeef);
1076 ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1077 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1078 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1080 /* Test nonexistent command line parameter. */
1081 SetLastError(0xdeadbeef);
1082 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1083 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1084 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1086 SetLastError(0xdeadbeef);
1087 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1088 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1089 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1092 static void test_Directory(void)
1094 char buffer[MAX_PATH];
1095 PROCESS_INFORMATION info;
1096 STARTUPINFOA startup;
1097 char windir[MAX_PATH];
1098 static CHAR cmdline[] = "winver.exe";
1100 memset(&startup, 0, sizeof(startup));
1101 startup.cb = sizeof(startup);
1102 startup.dwFlags = STARTF_USESHOWWINDOW;
1103 startup.wShowWindow = SW_SHOWNORMAL;
1105 /* the basics */
1106 get_file_name(resfile);
1107 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1108 GetWindowsDirectoryA( windir, sizeof(windir) );
1109 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n");
1110 /* wait for child to terminate */
1111 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1112 /* child process has changed result file, so let profile functions know about it */
1113 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1114 CloseHandle(info.hThread);
1115 CloseHandle(info.hProcess);
1117 okChildIString("Misc", "CurrDirA", windir);
1118 release_memory();
1119 DeleteFileA(resfile);
1121 /* search PATH for the exe if directory is NULL */
1122 ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1123 ok(TerminateProcess(info.hProcess, 0), "Child process termination\n");
1124 CloseHandle(info.hThread);
1125 CloseHandle(info.hProcess);
1127 /* if any directory is provided, don't search PATH, error on bad directory */
1128 SetLastError(0xdeadbeef);
1129 memset(&info, 0, sizeof(info));
1130 ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L,
1131 NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n");
1132 ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1133 ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n");
1136 static void test_Toolhelp(void)
1138 char buffer[MAX_PATH];
1139 STARTUPINFOA startup;
1140 PROCESS_INFORMATION info;
1141 HANDLE process, thread, snapshot;
1142 PROCESSENTRY32 pe;
1143 THREADENTRY32 te;
1144 DWORD ret;
1145 int i;
1147 memset(&startup, 0, sizeof(startup));
1148 startup.cb = sizeof(startup);
1149 startup.dwFlags = STARTF_USESHOWWINDOW;
1150 startup.wShowWindow = SW_SHOWNORMAL;
1152 get_file_name(resfile);
1153 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1154 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1155 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1156 CloseHandle(info.hProcess);
1157 CloseHandle(info.hThread);
1159 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1160 okChildInt("Toolhelp", "cntUsage", 0);
1161 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1162 okChildInt("Toolhelp", "th32ModuleID", 0);
1163 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1164 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1165 okChildInt("Toolhelp", "dwFlags", 0);
1167 release_memory();
1168 DeleteFileA(resfile);
1170 get_file_name(resfile);
1171 sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile);
1172 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1173 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1175 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1176 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1177 CloseHandle(process);
1179 CloseHandle(info.hProcess);
1180 CloseHandle(info.hThread);
1182 for (i = 0; i < 20; i++)
1184 SetLastError(0xdeadbeef);
1185 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1186 ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError());
1187 if (!process) break;
1188 CloseHandle(process);
1189 Sleep(100);
1191 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1192 ok(i < 20 || broken(i == 20), "process object not released\n");
1194 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1195 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1196 memset(&pe, 0, sizeof(pe));
1197 pe.dwSize = sizeof(pe);
1198 if (pProcess32First(snapshot, &pe))
1200 while (pe.th32ParentProcessID != info.dwProcessId)
1201 if (!pProcess32Next(snapshot, &pe)) break;
1203 CloseHandle(snapshot);
1204 ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n");
1206 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID);
1207 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1209 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1210 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1211 memset(&te, 0, sizeof(te));
1212 te.dwSize = sizeof(te);
1213 if (pThread32First(snapshot, &te))
1215 while (te.th32OwnerProcessID != pe.th32ProcessID)
1216 if (!pThread32Next(snapshot, &te)) break;
1218 CloseHandle(snapshot);
1219 ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1221 thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID);
1222 ok(thread != NULL, "OpenThread failed %u\n", GetLastError());
1223 ret = ResumeThread(thread);
1224 ok(ret == 1, "expected 1, got %u\n", ret);
1225 CloseHandle(thread);
1227 ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1228 CloseHandle(process);
1230 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1231 okChildInt("Toolhelp", "cntUsage", 0);
1232 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1233 okChildInt("Toolhelp", "th32ModuleID", 0);
1234 okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1235 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1236 okChildInt("Toolhelp", "dwFlags", 0);
1238 release_memory();
1239 DeleteFileA(resfile);
1242 static BOOL is_str_env_drive_dir(const char* str)
1244 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1245 str[3] == '=' && str[4] == str[1];
1248 /* compared expected child's environment (in gesA) from actual
1249 * environment our child got
1251 static void cmpEnvironment(const char* gesA)
1253 int i, clen;
1254 const char* ptrA;
1255 char* res;
1256 char key[32];
1257 BOOL found;
1259 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1261 /* now look each parent env in child */
1262 if ((ptrA = gesA) != NULL)
1264 while (*ptrA)
1266 for (i = 0; i < clen; i++)
1268 sprintf(key, "env%d", i);
1269 res = getChildString("EnvironmentA", key);
1270 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1271 break;
1273 found = i < clen;
1274 ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1276 ptrA += strlen(ptrA) + 1;
1277 release_memory();
1280 /* and each child env in parent */
1281 for (i = 0; i < clen; i++)
1283 sprintf(key, "env%d", i);
1284 res = getChildString("EnvironmentA", key);
1285 if ((ptrA = gesA) != NULL)
1287 while (*ptrA)
1289 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1290 break;
1291 ptrA += strlen(ptrA) + 1;
1293 if (!*ptrA) ptrA = NULL;
1296 if (!is_str_env_drive_dir(res))
1298 found = ptrA != NULL;
1299 ok(found, "Child-env string %s isn't in parent process\n", res);
1301 /* else => should also test we get the right per drive default directory here... */
1305 static void test_Environment(void)
1307 char buffer[MAX_PATH];
1308 PROCESS_INFORMATION info;
1309 STARTUPINFOA startup;
1310 char *child_env;
1311 int child_env_len;
1312 char *ptr;
1313 char *ptr2;
1314 char *env;
1315 int slen;
1317 memset(&startup, 0, sizeof(startup));
1318 startup.cb = sizeof(startup);
1319 startup.dwFlags = STARTF_USESHOWWINDOW;
1320 startup.wShowWindow = SW_SHOWNORMAL;
1322 /* the basics */
1323 get_file_name(resfile);
1324 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1325 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1326 /* wait for child to terminate */
1327 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1328 /* child process has changed result file, so let profile functions know about it */
1329 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1331 env = GetEnvironmentStringsA();
1332 cmpEnvironment(env);
1333 release_memory();
1334 DeleteFileA(resfile);
1336 memset(&startup, 0, sizeof(startup));
1337 startup.cb = sizeof(startup);
1338 startup.dwFlags = STARTF_USESHOWWINDOW;
1339 startup.wShowWindow = SW_SHOWNORMAL;
1341 /* the basics */
1342 get_file_name(resfile);
1343 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1345 child_env_len = 0;
1346 ptr = env;
1347 while(*ptr)
1349 slen = strlen(ptr)+1;
1350 child_env_len += slen;
1351 ptr += slen;
1353 /* Add space for additional environment variables */
1354 child_env_len += 256;
1355 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1357 ptr = child_env;
1358 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1359 ptr += strlen(ptr) + 1;
1360 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1361 ptr += strlen(ptr) + 1;
1362 strcpy(ptr, "FOO=BAR");
1363 ptr += strlen(ptr) + 1;
1364 strcpy(ptr, "BAR=FOOBAR");
1365 ptr += strlen(ptr) + 1;
1366 /* copy all existing variables except:
1367 * - WINELOADER
1368 * - PATH (already set above)
1369 * - the directory definitions (=[A-Z]:=)
1371 for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1373 if (strncmp(ptr2, "PATH=", 5) != 0 &&
1374 strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1375 !is_str_env_drive_dir(ptr2))
1377 strcpy(ptr, ptr2);
1378 ptr += strlen(ptr) + 1;
1381 *ptr = '\0';
1382 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1383 /* wait for child to terminate */
1384 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1385 /* child process has changed result file, so let profile functions know about it */
1386 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1388 cmpEnvironment(child_env);
1390 HeapFree(GetProcessHeap(), 0, child_env);
1391 FreeEnvironmentStringsA(env);
1392 release_memory();
1393 DeleteFileA(resfile);
1396 static void test_SuspendFlag(void)
1398 char buffer[MAX_PATH];
1399 PROCESS_INFORMATION info;
1400 STARTUPINFOA startup, us;
1401 DWORD exit_status;
1402 char *result;
1404 /* let's start simplistic */
1405 memset(&startup, 0, sizeof(startup));
1406 startup.cb = sizeof(startup);
1407 startup.dwFlags = STARTF_USESHOWWINDOW;
1408 startup.wShowWindow = SW_SHOWNORMAL;
1410 get_file_name(resfile);
1411 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1412 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1414 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1415 Sleep(1000);
1416 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1417 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1419 /* wait for child to terminate */
1420 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1421 /* child process has changed result file, so let profile functions know about it */
1422 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1424 GetStartupInfoA(&us);
1426 okChildInt("StartupInfoA", "cb", startup.cb);
1427 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1428 result = getChildString( "StartupInfoA", "lpTitle" );
1429 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1430 "expected '%s' or null, got '%s'\n", selfname, result );
1431 okChildInt("StartupInfoA", "dwX", startup.dwX);
1432 okChildInt("StartupInfoA", "dwY", startup.dwY);
1433 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1434 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1435 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1436 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1437 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1438 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1439 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1440 release_memory();
1441 DeleteFileA(resfile);
1444 static void test_DebuggingFlag(void)
1446 char buffer[MAX_PATH];
1447 void *processbase = NULL;
1448 PROCESS_INFORMATION info;
1449 STARTUPINFOA startup, us;
1450 DEBUG_EVENT de;
1451 unsigned dbg = 0;
1452 char *result;
1454 /* let's start simplistic */
1455 memset(&startup, 0, sizeof(startup));
1456 startup.cb = sizeof(startup);
1457 startup.dwFlags = STARTF_USESHOWWINDOW;
1458 startup.wShowWindow = SW_SHOWNORMAL;
1460 get_file_name(resfile);
1461 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1462 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1464 /* get all startup events up to the entry point break exception */
1467 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1468 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1469 if (!dbg)
1471 ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1472 "first event: %d\n", de.dwDebugEventCode);
1473 processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1475 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1476 ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT ||
1477 de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1478 } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1480 ok(dbg, "I have seen a debug event\n");
1481 /* wait for child to terminate */
1482 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1483 /* child process has changed result file, so let profile functions know about it */
1484 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1486 GetStartupInfoA(&us);
1488 okChildInt("StartupInfoA", "cb", startup.cb);
1489 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1490 result = getChildString( "StartupInfoA", "lpTitle" );
1491 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1492 "expected '%s' or null, got '%s'\n", selfname, result );
1493 okChildInt("StartupInfoA", "dwX", startup.dwX);
1494 okChildInt("StartupInfoA", "dwY", startup.dwY);
1495 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1496 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1497 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1498 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1499 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1500 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1501 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1502 release_memory();
1503 DeleteFileA(resfile);
1506 static BOOL is_console(HANDLE h)
1508 return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1511 static void test_Console(void)
1513 char buffer[MAX_PATH];
1514 PROCESS_INFORMATION info;
1515 STARTUPINFOA startup, us;
1516 SECURITY_ATTRIBUTES sa;
1517 CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC;
1518 DWORD modeIn, modeOut, modeInC, modeOutC;
1519 DWORD cpIn, cpOut, cpInC, cpOutC;
1520 DWORD w;
1521 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1522 const char* msg = "This is a std-handle inheritance test.";
1523 unsigned msg_len;
1524 BOOL run_tests = TRUE;
1525 char *result;
1527 memset(&startup, 0, sizeof(startup));
1528 startup.cb = sizeof(startup);
1529 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1530 startup.wShowWindow = SW_SHOWNORMAL;
1532 sa.nLength = sizeof(sa);
1533 sa.lpSecurityDescriptor = NULL;
1534 sa.bInheritHandle = TRUE;
1536 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1537 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1539 /* first, we need to be sure we're attached to a console */
1540 if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1542 /* we're not attached to a console, let's do it */
1543 AllocConsole();
1544 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1545 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1547 /* now verify everything's ok */
1548 ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1549 ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1550 startup.hStdError = startup.hStdOutput;
1552 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1553 ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1554 ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1555 cpIn = GetConsoleCP();
1556 cpOut = GetConsoleOutputCP();
1558 get_file_name(resfile);
1559 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile);
1560 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1562 /* wait for child to terminate */
1563 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1564 /* child process has changed result file, so let profile functions know about it */
1565 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1567 /* now get the modification the child has made, and resets parents expected values */
1568 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1569 ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1570 ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1572 SetConsoleMode(startup.hStdInput, modeIn);
1573 SetConsoleMode(startup.hStdOutput, modeOut);
1575 cpInC = GetConsoleCP();
1576 cpOutC = GetConsoleOutputCP();
1578 /* Try to set invalid CP */
1579 SetLastError(0xdeadbeef);
1580 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1581 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1582 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1583 "GetLastError: expecting %u got %u\n",
1584 ERROR_INVALID_PARAMETER, GetLastError());
1585 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1586 run_tests = FALSE;
1589 SetLastError(0xdeadbeef);
1590 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1591 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1592 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1593 "GetLastError: expecting %u got %u\n",
1594 ERROR_INVALID_PARAMETER, GetLastError());
1596 SetConsoleCP(cpIn);
1597 SetConsoleOutputCP(cpOut);
1599 GetStartupInfoA(&us);
1601 okChildInt("StartupInfoA", "cb", startup.cb);
1602 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1603 result = getChildString( "StartupInfoA", "lpTitle" );
1604 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1605 "expected '%s' or null, got '%s'\n", selfname, result );
1606 okChildInt("StartupInfoA", "dwX", startup.dwX);
1607 okChildInt("StartupInfoA", "dwY", startup.dwY);
1608 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1609 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1610 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1611 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1612 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1613 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1614 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1616 /* check child correctly inherited the console */
1617 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1618 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1619 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1620 okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1621 okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1622 okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1623 okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1624 okChildInt("Console", "Attributes", sbi.wAttributes);
1625 okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1626 okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1627 okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1628 okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1629 okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1630 okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1631 okChildInt("Console", "InputCP", cpIn);
1632 okChildInt("Console", "OutputCP", cpOut);
1633 okChildInt("Console", "InputMode", modeIn);
1634 okChildInt("Console", "OutputMode", modeOut);
1636 if (run_tests)
1638 ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1639 ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1641 else
1642 win_skip("Setting the codepage is not implemented\n");
1644 ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1645 ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1646 trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1647 ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1649 release_memory();
1650 DeleteFileA(resfile);
1652 ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1653 ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(),
1654 &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1655 "Duplicating as inheritable child-output pipe\n");
1656 CloseHandle(hChildOut);
1658 ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1659 ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(),
1660 &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1661 "Duplicating as inheritable child-input pipe\n");
1662 CloseHandle(hChildIn);
1664 memset(&startup, 0, sizeof(startup));
1665 startup.cb = sizeof(startup);
1666 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1667 startup.wShowWindow = SW_SHOWNORMAL;
1668 startup.hStdInput = hChildInInh;
1669 startup.hStdOutput = hChildOutInh;
1670 startup.hStdError = hChildOutInh;
1672 get_file_name(resfile);
1673 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile);
1674 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1675 ok(CloseHandle(hChildInInh), "Closing handle\n");
1676 ok(CloseHandle(hChildOutInh), "Closing handle\n");
1678 msg_len = strlen(msg) + 1;
1679 ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1680 ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1681 memset(buffer, 0, sizeof(buffer));
1682 ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1683 ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1685 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1686 ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1688 /* wait for child to terminate */
1689 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1690 /* child process has changed result file, so let profile functions know about it */
1691 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1693 okChildString("StdHandle", "msg", msg);
1695 release_memory();
1696 DeleteFileA(resfile);
1699 static void test_ExitCode(void)
1701 char buffer[MAX_PATH];
1702 PROCESS_INFORMATION info;
1703 STARTUPINFOA startup;
1704 DWORD code;
1706 /* let's start simplistic */
1707 memset(&startup, 0, sizeof(startup));
1708 startup.cb = sizeof(startup);
1709 startup.dwFlags = STARTF_USESHOWWINDOW;
1710 startup.wShowWindow = SW_SHOWNORMAL;
1712 get_file_name(resfile);
1713 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile);
1714 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1716 /* wait for child to terminate */
1717 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1718 /* child process has changed result file, so let profile functions know about it */
1719 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1721 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1722 okChildInt("ExitCode", "value", code);
1724 release_memory();
1725 DeleteFileA(resfile);
1728 static void test_OpenProcess(void)
1730 HANDLE hproc;
1731 void *addr1;
1732 MEMORY_BASIC_INFORMATION info;
1733 SIZE_T dummy, read_bytes;
1734 BOOL ret;
1736 /* not exported in all windows versions */
1737 if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1738 win_skip("VirtualAllocEx not found\n");
1739 return;
1742 /* without PROCESS_VM_OPERATION */
1743 hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1744 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1746 SetLastError(0xdeadbeef);
1747 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1748 ok(!addr1, "VirtualAllocEx should fail\n");
1749 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1750 { /* Win9x */
1751 CloseHandle(hproc);
1752 win_skip("VirtualAllocEx not implemented\n");
1753 return;
1755 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1757 read_bytes = 0xdeadbeef;
1758 SetLastError(0xdeadbeef);
1759 ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes);
1760 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1761 ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1763 CloseHandle(hproc);
1765 hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1766 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1768 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1769 ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1771 /* without PROCESS_QUERY_INFORMATION */
1772 SetLastError(0xdeadbeef);
1773 ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1774 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1775 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1777 /* without PROCESS_VM_READ */
1778 read_bytes = 0xdeadbeef;
1779 SetLastError(0xdeadbeef);
1780 ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1781 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1782 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1783 ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1785 CloseHandle(hproc);
1787 hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1789 memset(&info, 0xcc, sizeof(info));
1790 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1791 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1793 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1794 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1795 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1796 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1797 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1798 /* NT reports Protect == 0 for a not committed memory block */
1799 ok(info.Protect == 0 /* NT */ ||
1800 info.Protect == PAGE_NOACCESS, /* Win9x */
1801 "%x != PAGE_NOACCESS\n", info.Protect);
1802 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1804 SetLastError(0xdeadbeef);
1805 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1806 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1807 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1809 CloseHandle(hproc);
1811 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1812 if (hproc)
1814 SetLastError(0xdeadbeef);
1815 memset(&info, 0xcc, sizeof(info));
1816 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1817 if (read_bytes) /* win8 */
1819 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1820 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1821 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1822 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1823 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1824 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1825 ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
1826 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1828 else /* before win8 */
1829 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1831 SetLastError(0xdeadbeef);
1832 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1833 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1834 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1836 CloseHandle(hproc);
1839 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1842 static void test_GetProcessVersion(void)
1844 static char cmdline[] = "winver.exe";
1845 PROCESS_INFORMATION pi;
1846 STARTUPINFOA si;
1847 DWORD ret;
1849 SetLastError(0xdeadbeef);
1850 ret = GetProcessVersion(0);
1851 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1853 SetLastError(0xdeadbeef);
1854 ret = GetProcessVersion(GetCurrentProcessId());
1855 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1857 memset(&si, 0, sizeof(si));
1858 si.cb = sizeof(si);
1859 si.dwFlags = STARTF_USESHOWWINDOW;
1860 si.wShowWindow = SW_HIDE;
1861 SetLastError(0xdeadbeef);
1862 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1863 ok(ret, "CreateProcess error %u\n", GetLastError());
1865 SetLastError(0xdeadbeef);
1866 ret = GetProcessVersion(pi.dwProcessId);
1867 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1869 SetLastError(0xdeadbeef);
1870 ret = TerminateProcess(pi.hProcess, 0);
1871 ok(ret, "TerminateProcess error %u\n", GetLastError());
1873 CloseHandle(pi.hProcess);
1874 CloseHandle(pi.hThread);
1877 static void test_GetProcessImageFileNameA(void)
1879 DWORD rc;
1880 CHAR process[MAX_PATH];
1881 static const char harddisk[] = "\\Device\\HarddiskVolume";
1883 if (!pK32GetProcessImageFileNameA)
1885 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1886 return;
1889 /* callers must guess the buffer size */
1890 SetLastError(0xdeadbeef);
1891 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1892 ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1893 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError());
1895 *process = '\0';
1896 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1897 expect_eq_d(rc, lstrlenA(process));
1898 if (strncmp(process, harddisk, lstrlenA(harddisk)))
1900 todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1901 return;
1904 if (!pQueryFullProcessImageNameA)
1905 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1906 else
1908 CHAR image[MAX_PATH];
1909 DWORD length;
1911 length = sizeof(image);
1912 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1913 expect_eq_d(length, lstrlenA(image));
1914 ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1918 static void test_QueryFullProcessImageNameA(void)
1920 #define INIT_STR "Just some words"
1921 DWORD length, size;
1922 CHAR buf[MAX_PATH], module[MAX_PATH];
1924 if (!pQueryFullProcessImageNameA)
1926 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1927 return;
1930 *module = '\0';
1931 SetLastError(0); /* old Windows don't reset it on success */
1932 size = GetModuleFileNameA(NULL, module, sizeof(module));
1933 ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError());
1935 /* get the buffer length without \0 terminator */
1936 length = sizeof(buf);
1937 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1938 expect_eq_d(length, lstrlenA(buf));
1939 ok((buf[0] == '\\' && buf[1] == '\\') ||
1940 lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1942 /* when the buffer is too small
1943 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1944 * - the size variable is not modified
1945 * tested with the biggest too small size
1947 size = length;
1948 sprintf(buf,INIT_STR);
1949 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1950 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1951 expect_eq_d(length, size);
1952 expect_eq_s(INIT_STR, buf);
1954 /* retest with smaller buffer size
1956 size = 4;
1957 sprintf(buf,INIT_STR);
1958 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1959 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1960 expect_eq_d(4, size);
1961 expect_eq_s(INIT_STR, buf);
1963 /* this is a difference between the ascii and the unicode version
1964 * the unicode version crashes when the size is big enough to hold
1965 * the result while the ascii version throws an error
1967 size = 1024;
1968 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1969 expect_eq_d(1024, size);
1970 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
1973 static void test_QueryFullProcessImageNameW(void)
1975 HANDLE hSelf;
1976 WCHAR module_name[1024], device[1024];
1977 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
1978 WCHAR buf[1024];
1979 DWORD size, len;
1981 if (!pQueryFullProcessImageNameW)
1983 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1984 return;
1987 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1989 /* GetCurrentProcess pseudo-handle */
1990 size = sizeof(buf) / sizeof(buf[0]);
1991 expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
1992 expect_eq_d(lstrlenW(buf), size);
1993 expect_eq_ws_i(buf, module_name);
1995 hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1996 /* Real handle */
1997 size = sizeof(buf) / sizeof(buf[0]);
1998 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1999 expect_eq_d(lstrlenW(buf), size);
2000 expect_eq_ws_i(buf, module_name);
2002 /* Buffer too small */
2003 size = lstrlenW(module_name)/2;
2004 lstrcpyW(buf, deviceW);
2005 SetLastError(0xdeadbeef);
2006 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2007 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2008 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2009 expect_eq_ws_i(deviceW, buf); /* buffer not changed */
2011 /* Too small - not space for NUL terminator */
2012 size = lstrlenW(module_name);
2013 SetLastError(0xdeadbeef);
2014 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2015 expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
2016 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2018 /* NULL buffer */
2019 size = 0;
2020 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
2021 expect_eq_d(0, size);
2022 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2024 /* Buffer too small */
2025 size = lstrlenW(module_name)/2;
2026 SetLastError(0xdeadbeef);
2027 lstrcpyW(buf, module_name);
2028 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2029 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2030 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2031 expect_eq_ws_i(module_name, buf); /* buffer not changed */
2034 /* native path */
2035 size = sizeof(buf) / sizeof(buf[0]);
2036 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2037 expect_eq_d(lstrlenW(buf), size);
2038 ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2039 ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2041 module_name[2] = '\0';
2042 *device = '\0';
2043 size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0]));
2044 ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2045 len = lstrlenW(device);
2046 ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2048 if (size >= lstrlenW(buf))
2050 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2052 else
2054 ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2055 buf[len] = '\0';
2056 ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2057 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));
2060 CloseHandle(hSelf);
2063 static void test_Handles(void)
2065 HANDLE handle = GetCurrentProcess();
2066 HANDLE h2, h3;
2067 BOOL ret;
2068 DWORD code;
2070 ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2071 handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2072 "invalid current process handle %p\n", handle );
2073 ret = GetExitCodeProcess( handle, &code );
2074 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2075 #ifdef _WIN64
2076 /* truncated handle */
2077 SetLastError( 0xdeadbeef );
2078 handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2079 ret = GetExitCodeProcess( handle, &code );
2080 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2081 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2082 /* sign-extended handle */
2083 SetLastError( 0xdeadbeef );
2084 handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle);
2085 ret = GetExitCodeProcess( handle, &code );
2086 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2087 /* invalid high-word */
2088 SetLastError( 0xdeadbeef );
2089 handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2090 ret = GetExitCodeProcess( handle, &code );
2091 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2092 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2093 #endif
2095 handle = GetStdHandle( STD_ERROR_HANDLE );
2096 ok( handle != 0, "handle %p\n", handle );
2097 DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &h3,
2098 0, TRUE, DUPLICATE_SAME_ACCESS );
2099 SetStdHandle( STD_ERROR_HANDLE, h3 );
2100 CloseHandle( (HANDLE)STD_ERROR_HANDLE );
2101 h2 = GetStdHandle( STD_ERROR_HANDLE );
2102 ok( h2 == 0 ||
2103 broken( h2 == h3) || /* nt4, w2k */
2104 broken( h2 == INVALID_HANDLE_VALUE), /* win9x */
2105 "wrong handle %p/%p\n", h2, h3 );
2106 SetStdHandle( STD_ERROR_HANDLE, handle );
2109 static void test_IsWow64Process(void)
2111 PROCESS_INFORMATION pi;
2112 STARTUPINFOA si;
2113 DWORD ret;
2114 BOOL is_wow64;
2115 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2116 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2118 if (!pIsWow64Process)
2120 skip("IsWow64Process is not available\n");
2121 return;
2124 memset(&si, 0, sizeof(si));
2125 si.cb = sizeof(si);
2126 si.dwFlags = STARTF_USESHOWWINDOW;
2127 si.wShowWindow = SW_HIDE;
2128 ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2129 if (ret)
2131 trace("Created process %s\n", cmdline_wow64);
2132 is_wow64 = FALSE;
2133 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2134 ok(ret, "IsWow64Process failed.\n");
2135 ok(is_wow64, "is_wow64 returned FALSE.\n");
2137 ret = TerminateProcess(pi.hProcess, 0);
2138 ok(ret, "TerminateProcess error\n");
2140 CloseHandle(pi.hProcess);
2141 CloseHandle(pi.hThread);
2144 memset(&si, 0, sizeof(si));
2145 si.cb = sizeof(si);
2146 si.dwFlags = STARTF_USESHOWWINDOW;
2147 si.wShowWindow = SW_HIDE;
2148 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2149 if (ret)
2151 trace("Created process %s\n", cmdline);
2152 is_wow64 = TRUE;
2153 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2154 ok(ret, "IsWow64Process failed.\n");
2155 ok(!is_wow64, "is_wow64 returned TRUE.\n");
2157 ret = TerminateProcess(pi.hProcess, 0);
2158 ok(ret, "TerminateProcess error\n");
2160 CloseHandle(pi.hProcess);
2161 CloseHandle(pi.hThread);
2165 static void test_SystemInfo(void)
2167 SYSTEM_INFO si, nsi;
2168 BOOL is_wow64;
2170 if (!pGetNativeSystemInfo)
2172 win_skip("GetNativeSystemInfo is not available\n");
2173 return;
2176 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2178 GetSystemInfo(&si);
2179 pGetNativeSystemInfo(&nsi);
2180 if (is_wow64)
2182 if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2184 ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2185 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2186 S(U(nsi)).wProcessorArchitecture);
2187 ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664,
2188 "Expected PROCESSOR_AMD_X8664, got %d\n",
2189 nsi.dwProcessorType);
2192 else
2194 ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2195 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2196 S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2197 ok(si.dwProcessorType == nsi.dwProcessorType,
2198 "Expected no difference for dwProcessorType, got %d and %d\n",
2199 si.dwProcessorType, nsi.dwProcessorType);
2203 static void test_RegistryQuota(void)
2205 BOOL ret;
2206 DWORD max_quota, used_quota;
2208 if (!pGetSystemRegistryQuota)
2210 win_skip("GetSystemRegistryQuota is not available\n");
2211 return;
2214 ret = pGetSystemRegistryQuota(NULL, NULL);
2215 ok(ret == TRUE,
2216 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2218 ret = pGetSystemRegistryQuota(&max_quota, NULL);
2219 ok(ret == TRUE,
2220 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2222 ret = pGetSystemRegistryQuota(NULL, &used_quota);
2223 ok(ret == TRUE,
2224 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2226 ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2227 ok(ret == TRUE,
2228 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2231 static void test_TerminateProcess(void)
2233 static char cmdline[] = "winver.exe";
2234 PROCESS_INFORMATION pi;
2235 STARTUPINFOA si;
2236 DWORD ret;
2237 HANDLE dummy, thread;
2239 memset(&si, 0, sizeof(si));
2240 si.cb = sizeof(si);
2241 SetLastError(0xdeadbeef);
2242 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2243 ok(ret, "CreateProcess error %u\n", GetLastError());
2245 SetLastError(0xdeadbeef);
2246 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2247 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2249 /* create a not closed thread handle duplicate in the target process */
2250 SetLastError(0xdeadbeef);
2251 ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy,
2252 0, FALSE, DUPLICATE_SAME_ACCESS);
2253 ok(ret, "DuplicateHandle error %u\n", GetLastError());
2255 SetLastError(0xdeadbeef);
2256 ret = TerminateThread(thread, 0);
2257 ok(ret, "TerminateThread error %u\n", GetLastError());
2258 CloseHandle(thread);
2260 SetLastError(0xdeadbeef);
2261 ret = TerminateProcess(pi.hProcess, 0);
2262 ok(ret, "TerminateProcess error %u\n", GetLastError());
2264 CloseHandle(pi.hProcess);
2265 CloseHandle(pi.hThread);
2268 static void test_DuplicateHandle(void)
2270 char path[MAX_PATH], file_name[MAX_PATH];
2271 HANDLE f, fmin, out;
2272 DWORD info;
2273 BOOL r;
2275 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2276 GetCurrentProcess(), &out, 0, FALSE,
2277 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2278 ok(r, "DuplicateHandle error %u\n", GetLastError());
2279 r = GetHandleInformation(out, &info);
2280 ok(r, "GetHandleInformation error %u\n", GetLastError());
2281 ok(info == 0, "info = %x\n", info);
2282 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2283 CloseHandle(out);
2285 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2286 GetCurrentProcess(), &out, 0, TRUE,
2287 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2288 ok(r, "DuplicateHandle error %u\n", GetLastError());
2289 r = GetHandleInformation(out, &info);
2290 ok(r, "GetHandleInformation error %u\n", GetLastError());
2291 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2292 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2293 CloseHandle(out);
2295 GetTempPathA(MAX_PATH, path);
2296 GetTempFileNameA(path, "wt", 0, file_name);
2297 f = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2298 if (f == INVALID_HANDLE_VALUE)
2300 ok(0, "could not create %s\n", file_name);
2301 return;
2304 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2305 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2306 ok(r, "DuplicateHandle error %u\n", GetLastError());
2307 ok(f == out, "f != out\n");
2308 r = GetHandleInformation(out, &info);
2309 ok(r, "GetHandleInformation error %u\n", GetLastError());
2310 ok(info == 0, "info = %x\n", info);
2312 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2313 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2314 ok(r, "DuplicateHandle error %u\n", GetLastError());
2315 ok(f == out, "f != out\n");
2316 r = GetHandleInformation(out, &info);
2317 ok(r, "GetHandleInformation error %u\n", GetLastError());
2318 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2320 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
2321 ok(r, "SetHandleInformation error %u\n", GetLastError());
2322 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2323 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2324 ok(r, "DuplicateHandle error %u\n", GetLastError());
2325 ok(f != out, "f == out\n");
2326 r = GetHandleInformation(out, &info);
2327 ok(r, "GetHandleInformation error %u\n", GetLastError());
2328 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2329 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2330 ok(r, "SetHandleInformation error %u\n", GetLastError());
2332 /* Test if DuplicateHandle allocates first free handle */
2333 if (f > out)
2335 fmin = out;
2337 else
2339 fmin = f;
2340 f = out;
2342 CloseHandle(fmin);
2343 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2344 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2345 ok(r, "DuplicateHandle error %u\n", GetLastError());
2346 ok(f == out, "f != out\n");
2347 CloseHandle(out);
2348 DeleteFileA(file_name);
2350 f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2351 if (!is_console(f))
2353 skip("DuplicateHandle on console handle\n");
2354 CloseHandle(f);
2355 return;
2358 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2359 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2360 ok(r, "DuplicateHandle error %u\n", GetLastError());
2361 todo_wine ok(f != out, "f == out\n");
2362 CloseHandle(out);
2365 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2366 static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2368 LPOVERLAPPED overlapped;
2369 ULONG_PTR value;
2370 DWORD key;
2371 BOOL ret;
2373 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait);
2375 ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
2376 if (ret)
2378 ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key);
2379 ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2380 ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2384 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2385 static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2387 BOOL ret;
2388 char buffer[MAX_PATH];
2389 STARTUPINFOA si = {0};
2391 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command);
2393 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2394 ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError());
2398 static void test_IsProcessInJob(void)
2400 HANDLE job, job2;
2401 PROCESS_INFORMATION pi;
2402 BOOL ret, out;
2403 DWORD dwret;
2405 if (!pIsProcessInJob)
2407 win_skip("IsProcessInJob not available.\n");
2408 return;
2411 job = pCreateJobObjectW(NULL, NULL);
2412 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2414 job2 = pCreateJobObjectW(NULL, NULL);
2415 ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError());
2417 create_process("wait", &pi);
2419 out = TRUE;
2420 ret = pIsProcessInJob(pi.hProcess, job, &out);
2421 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2422 ok(!out, "IsProcessInJob returned out=%u\n", out);
2424 out = TRUE;
2425 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2426 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2427 ok(!out, "IsProcessInJob returned out=%u\n", out);
2429 out = TRUE;
2430 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2431 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2432 ok(!out, "IsProcessInJob returned out=%u\n", out);
2434 ret = pAssignProcessToJobObject(job, pi.hProcess);
2435 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2437 out = FALSE;
2438 ret = pIsProcessInJob(pi.hProcess, job, &out);
2439 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2440 ok(out, "IsProcessInJob returned out=%u\n", out);
2442 out = TRUE;
2443 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2444 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2445 ok(!out, "IsProcessInJob returned out=%u\n", out);
2447 out = FALSE;
2448 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2449 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2450 ok(out, "IsProcessInJob returned out=%u\n", out);
2452 TerminateProcess(pi.hProcess, 0);
2454 dwret = WaitForSingleObject(pi.hProcess, 1000);
2455 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2457 out = FALSE;
2458 ret = pIsProcessInJob(pi.hProcess, job, &out);
2459 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2460 ok(out, "IsProcessInJob returned out=%u\n", out);
2462 CloseHandle(pi.hProcess);
2463 CloseHandle(pi.hThread);
2464 CloseHandle(job);
2465 CloseHandle(job2);
2468 static void test_TerminateJobObject(void)
2470 HANDLE job;
2471 PROCESS_INFORMATION pi;
2472 BOOL ret;
2473 DWORD dwret;
2475 job = pCreateJobObjectW(NULL, NULL);
2476 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2478 create_process("wait", &pi);
2480 ret = pAssignProcessToJobObject(job, pi.hProcess);
2481 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2483 ret = pTerminateJobObject(job, 123);
2484 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2486 dwret = WaitForSingleObject(pi.hProcess, 1000);
2487 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2488 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2490 ret = GetExitCodeProcess(pi.hProcess, &dwret);
2491 ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
2492 ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
2493 "wrong exitcode %u\n", dwret);
2495 CloseHandle(pi.hProcess);
2496 CloseHandle(pi.hThread);
2498 /* Test adding an already terminated process to a job object */
2499 create_process("exit", &pi);
2501 dwret = WaitForSingleObject(pi.hProcess, 1000);
2502 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2504 SetLastError(0xdeadbeef);
2505 ret = pAssignProcessToJobObject(job, pi.hProcess);
2506 ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2507 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2509 CloseHandle(pi.hProcess);
2510 CloseHandle(pi.hThread);
2512 CloseHandle(job);
2515 static void test_QueryInformationJobObject(void)
2517 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2518 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2519 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2520 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2521 DWORD dwret, ret_len;
2522 PROCESS_INFORMATION pi[2];
2523 HANDLE job;
2524 BOOL ret;
2526 job = pCreateJobObjectW(NULL, NULL);
2527 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2529 /* Only active processes are returned */
2530 create_process("exit", &pi[0]);
2531 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2532 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2533 dwret = WaitForSingleObject(pi[0].hProcess, 1000);
2534 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2536 CloseHandle(pi[0].hProcess);
2537 CloseHandle(pi[0].hThread);
2539 create_process("wait", &pi[0]);
2540 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2541 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2543 create_process("wait", &pi[1]);
2544 ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2545 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2547 SetLastError(0xdeadbeef);
2548 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2549 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len);
2550 ok(!ret, "QueryInformationJobObject expected failure\n");
2551 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2553 SetLastError(0xdeadbeef);
2554 memset(buf, 0, sizeof(buf));
2555 pid_list->NumberOfAssignedProcesses = 42;
2556 pid_list->NumberOfProcessIdsInList = 42;
2557 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2558 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len);
2559 todo_wine
2560 ok(!ret, "QueryInformationJobObject expected failure\n");
2561 todo_wine
2562 expect_eq_d(ERROR_MORE_DATA, GetLastError());
2563 if (ret)
2565 todo_wine
2566 expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2567 todo_wine
2568 expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2571 memset(buf, 0, sizeof(buf));
2572 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2573 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2574 if(ret)
2576 if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2577 win_skip("Number of assigned processes broken on Win 8\n");
2578 else
2580 ULONG_PTR *list = pid_list->ProcessIdList;
2582 todo_wine
2583 ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]),
2584 "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2586 todo_wine
2587 expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2588 todo_wine
2589 expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2590 todo_wine
2591 expect_eq_d(pi[0].dwProcessId, list[0]);
2592 todo_wine
2593 expect_eq_d(pi[1].dwProcessId, list[1]);
2597 /* test JobObjectBasicLimitInformation */
2598 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2599 sizeof(*basic_limit_info) - 1, &ret_len);
2600 ok(!ret, "QueryInformationJobObject expected failure\n");
2601 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2603 ret_len = 0xdeadbeef;
2604 memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2605 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2606 sizeof(*basic_limit_info), &ret_len);
2607 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2608 ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2609 expect_eq_d(0, basic_limit_info->LimitFlags);
2611 /* test JobObjectExtendedLimitInformation */
2612 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2613 sizeof(ext_limit_info) - 1, &ret_len);
2614 ok(!ret, "QueryInformationJobObject expected failure\n");
2615 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2617 ret_len = 0xdeadbeef;
2618 memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2619 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2620 sizeof(ext_limit_info), &ret_len);
2621 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2622 ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2623 expect_eq_d(0, basic_limit_info->LimitFlags);
2625 TerminateProcess(pi[0].hProcess, 0);
2626 CloseHandle(pi[0].hProcess);
2627 CloseHandle(pi[0].hThread);
2629 TerminateProcess(pi[1].hProcess, 0);
2630 CloseHandle(pi[1].hProcess);
2631 CloseHandle(pi[1].hThread);
2633 CloseHandle(job);
2636 static void test_CompletionPort(void)
2638 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
2639 PROCESS_INFORMATION pi;
2640 HANDLE job, port;
2641 DWORD dwret;
2642 BOOL ret;
2644 job = pCreateJobObjectW(NULL, NULL);
2645 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2647 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2648 ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
2650 port_info.CompletionKey = job;
2651 port_info.CompletionPort = port;
2652 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2653 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2655 create_process("wait", &pi);
2657 ret = pAssignProcessToJobObject(job, pi.hProcess);
2658 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2660 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2662 TerminateProcess(pi.hProcess, 0);
2663 dwret = WaitForSingleObject(pi.hProcess, 1000);
2664 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2666 test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2667 test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100);
2669 CloseHandle(pi.hProcess);
2670 CloseHandle(pi.hThread);
2671 CloseHandle(job);
2672 CloseHandle(port);
2675 static void test_KillOnJobClose(void)
2677 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2678 PROCESS_INFORMATION pi;
2679 DWORD dwret;
2680 HANDLE job;
2681 BOOL ret;
2683 job = pCreateJobObjectW(NULL, NULL);
2684 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2686 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
2687 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2688 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2690 win_skip("Kill on job close limit not available\n");
2691 return;
2693 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2695 create_process("wait", &pi);
2697 ret = pAssignProcessToJobObject(job, pi.hProcess);
2698 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2700 CloseHandle(job);
2702 dwret = WaitForSingleObject(pi.hProcess, 1000);
2703 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2704 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2706 CloseHandle(pi.hProcess);
2707 CloseHandle(pi.hThread);
2710 static void test_WaitForJobObject(void)
2712 HANDLE job;
2713 PROCESS_INFORMATION pi;
2714 BOOL ret;
2715 DWORD dwret;
2717 /* test waiting for a job object when the process is killed */
2718 job = pCreateJobObjectW(NULL, NULL);
2719 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2721 dwret = WaitForSingleObject(job, 100);
2722 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2724 create_process("wait", &pi);
2726 ret = pAssignProcessToJobObject(job, pi.hProcess);
2727 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2729 dwret = WaitForSingleObject(job, 100);
2730 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2732 ret = pTerminateJobObject(job, 123);
2733 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2735 dwret = WaitForSingleObject(job, 500);
2736 ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2737 "WaitForSingleObject returned %u\n", dwret);
2739 if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2741 CloseHandle(pi.hProcess);
2742 CloseHandle(pi.hThread);
2743 CloseHandle(job);
2744 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2745 return;
2748 /* the object is not reset immediately */
2749 dwret = WaitForSingleObject(job, 100);
2750 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2752 CloseHandle(pi.hProcess);
2753 CloseHandle(pi.hThread);
2755 /* creating a new process doesn't reset the signalled state */
2756 create_process("wait", &pi);
2758 ret = pAssignProcessToJobObject(job, pi.hProcess);
2759 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2761 dwret = WaitForSingleObject(job, 100);
2762 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2764 ret = pTerminateJobObject(job, 123);
2765 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2767 CloseHandle(pi.hProcess);
2768 CloseHandle(pi.hThread);
2770 CloseHandle(job);
2772 /* repeat the test, but this time the process terminates properly */
2773 job = pCreateJobObjectW(NULL, NULL);
2774 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2776 dwret = WaitForSingleObject(job, 100);
2777 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2779 create_process("exit", &pi);
2781 ret = pAssignProcessToJobObject(job, pi.hProcess);
2782 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2784 dwret = WaitForSingleObject(job, 100);
2785 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2787 CloseHandle(pi.hProcess);
2788 CloseHandle(pi.hThread);
2789 CloseHandle(job);
2792 static HANDLE test_AddSelfToJob(void)
2794 HANDLE job;
2795 BOOL ret;
2797 job = pCreateJobObjectW(NULL, NULL);
2798 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2800 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2801 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2803 return job;
2806 static void test_jobInheritance(HANDLE job)
2808 char buffer[MAX_PATH];
2809 PROCESS_INFORMATION pi;
2810 STARTUPINFOA si = {0};
2811 DWORD dwret;
2812 BOOL ret, out;
2814 if (!pIsProcessInJob)
2816 win_skip("IsProcessInJob not available.\n");
2817 return;
2820 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2822 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2823 ok(ret, "CreateProcessA error %u\n", GetLastError());
2825 out = FALSE;
2826 ret = pIsProcessInJob(pi.hProcess, job, &out);
2827 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2828 ok(out, "IsProcessInJob returned out=%u\n", out);
2830 dwret = WaitForSingleObject(pi.hProcess, 1000);
2831 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2833 CloseHandle(pi.hProcess);
2834 CloseHandle(pi.hThread);
2837 static void test_BreakawayOk(HANDLE job)
2839 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2840 PROCESS_INFORMATION pi;
2841 STARTUPINFOA si = {0};
2842 char buffer[MAX_PATH];
2843 BOOL ret, out;
2844 DWORD dwret;
2846 if (!pIsProcessInJob)
2848 win_skip("IsProcessInJob not available.\n");
2849 return;
2852 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2854 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2855 ok(!ret, "CreateProcessA expected failure\n");
2856 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2858 if (ret)
2860 TerminateProcess(pi.hProcess, 0);
2862 dwret = WaitForSingleObject(pi.hProcess, 1000);
2863 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2865 CloseHandle(pi.hProcess);
2866 CloseHandle(pi.hThread);
2869 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
2870 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2871 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2873 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2874 ok(ret, "CreateProcessA error %u\n", GetLastError());
2876 ret = pIsProcessInJob(pi.hProcess, job, &out);
2877 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2878 ok(!out, "IsProcessInJob returned out=%u\n", out);
2880 dwret = WaitForSingleObject(pi.hProcess, 1000);
2881 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2883 CloseHandle(pi.hProcess);
2884 CloseHandle(pi.hThread);
2886 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
2887 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2888 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2890 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2891 ok(ret, "CreateProcess error %u\n", GetLastError());
2893 ret = pIsProcessInJob(pi.hProcess, job, &out);
2894 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2895 ok(!out, "IsProcessInJob returned out=%u\n", out);
2897 dwret = WaitForSingleObject(pi.hProcess, 1000);
2898 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2900 CloseHandle(pi.hProcess);
2901 CloseHandle(pi.hThread);
2903 /* unset breakaway ok */
2904 limit_info.BasicLimitInformation.LimitFlags = 0;
2905 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2906 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2909 static void test_StartupNoConsole(void)
2911 #ifndef _WIN64
2912 char buffer[MAX_PATH];
2913 STARTUPINFOA startup;
2914 PROCESS_INFORMATION info;
2916 memset(&startup, 0, sizeof(startup));
2917 startup.cb = sizeof(startup);
2918 startup.dwFlags = STARTF_USESHOWWINDOW;
2919 startup.wShowWindow = SW_SHOWNORMAL;
2920 get_file_name(resfile);
2921 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
2922 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
2923 &info), "CreateProcess\n");
2924 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
2925 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
2926 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
2927 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
2928 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
2929 okChildInt("TEB", "hStdInput", 0);
2930 okChildInt("TEB", "hStdOutput", 0);
2931 okChildInt("TEB", "hStdError", 0);
2932 release_memory();
2933 DeleteFileA(resfile);
2934 #endif
2937 static void test_DetachConsoleHandles(void)
2939 #ifndef _WIN64
2940 char buffer[MAX_PATH];
2941 STARTUPINFOA startup;
2942 PROCESS_INFORMATION info;
2943 UINT result;
2945 memset(&startup, 0, sizeof(startup));
2946 startup.cb = sizeof(startup);
2947 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
2948 startup.wShowWindow = SW_SHOWNORMAL;
2949 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
2950 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
2951 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2952 get_file_name(resfile);
2953 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
2954 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
2955 &info), "CreateProcess\n");
2956 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
2957 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
2959 result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile);
2960 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2961 result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile);
2962 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2963 result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile);
2964 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2965 result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile);
2966 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2967 result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile);
2968 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2969 result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile);
2970 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
2972 release_memory();
2973 DeleteFileA(resfile);
2974 #endif
2977 #if defined(__i386__) || defined(__x86_64__)
2978 static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi,
2979 IMAGE_NT_HEADERS *nt_header)
2981 IMAGE_DOS_HEADER dos_header;
2983 if (!ReadProcessMemory(process_handle, mbi->BaseAddress, &dos_header, sizeof(dos_header), NULL))
2984 return FALSE;
2986 if ((dos_header.e_magic != IMAGE_DOS_SIGNATURE) ||
2987 ((ULONG)dos_header.e_lfanew > mbi->RegionSize) ||
2988 (dos_header.e_lfanew < sizeof(dos_header)))
2989 return FALSE;
2991 if (!ReadProcessMemory(process_handle, (char *)mbi->BaseAddress + dos_header.e_lfanew,
2992 nt_header, sizeof(*nt_header), NULL))
2993 return FALSE;
2995 return (nt_header->Signature == IMAGE_NT_SIGNATURE);
2998 static PVOID get_process_exe(HANDLE process_handle, IMAGE_NT_HEADERS *nt_header)
3000 PVOID exe_base, address;
3001 MEMORY_BASIC_INFORMATION mbi;
3003 /* Find the EXE base in the new process */
3004 exe_base = NULL;
3005 for (address = NULL ;
3006 VirtualQueryEx(process_handle, address, &mbi, sizeof(mbi)) ;
3007 address = (char *)mbi.BaseAddress + mbi.RegionSize) {
3008 if ((mbi.Type == SEC_IMAGE) &&
3009 read_nt_header(process_handle, &mbi, nt_header) &&
3010 !(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
3011 exe_base = mbi.BaseAddress;
3012 break;
3016 return exe_base;
3019 static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE_NT_HEADERS *nt_header)
3021 BOOL ret;
3022 IMAGE_IMPORT_DESCRIPTOR iid;
3023 ULONG_PTR orig_iat_entry_value, iat_entry_value;
3025 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, "Import table VA is zero\n");
3026 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, "Import table Size is zero\n");
3028 if (!nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ||
3029 !nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
3030 return FALSE;
3032 /* Read the first IID */
3033 ret = ReadProcessMemory(process_handle,
3034 (char *)module_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
3035 &iid, sizeof(iid), NULL);
3036 ok(ret, "Failed to read remote module IID (%d)\n", GetLastError());
3038 /* Validate the IID is present and not a bound import, and that we have
3039 an OriginalFirstThunk to compare with */
3040 ok(iid.Name, "Module first IID does not have a Name\n");
3041 ok(iid.FirstThunk, "Module first IID does not have a FirstThunk\n");
3042 ok(!iid.TimeDateStamp, "Module first IID is a bound import (UNSUPPORTED for current test)\n");
3043 ok(iid.OriginalFirstThunk, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3045 /* Read a single IAT entry from the FirstThunk */
3046 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.FirstThunk,
3047 &iat_entry_value, sizeof(iat_entry_value), NULL);
3048 ok(ret, "Failed to read IAT entry from FirstThunk (%d)\n", GetLastError());
3049 ok(iat_entry_value, "IAT entry in FirstThunk is NULL\n");
3051 /* Read a single IAT entry from the OriginalFirstThunk */
3052 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.OriginalFirstThunk,
3053 &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL);
3054 ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%d)\n", GetLastError());
3055 ok(orig_iat_entry_value, "IAT entry in OriginalFirstThunk is NULL\n");
3057 return iat_entry_value != orig_iat_entry_value;
3060 static void test_SuspendProcessNewThread(void)
3062 BOOL ret;
3063 STARTUPINFOA si = {0};
3064 PROCESS_INFORMATION pi = {0};
3065 PVOID exe_base, exit_thread_ptr;
3066 IMAGE_NT_HEADERS nt_header;
3067 HANDLE thread_handle = NULL;
3068 DWORD dret, exit_code = 0;
3069 CONTEXT ctx;
3071 exit_thread_ptr = GetProcAddress(hkernel32, "ExitThread");
3072 ok(exit_thread_ptr != NULL, "GetProcAddress ExitThread failed\n");
3074 si.cb = sizeof(si);
3075 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3076 ok(ret, "Failed to create process (%d)\n", GetLastError());
3078 exe_base = get_process_exe(pi.hProcess, &nt_header);
3079 ok(exe_base != NULL, "Could not find EXE in remote process\n");
3081 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3082 ok(!ret, "IAT entry resolved prematurely\n");
3084 thread_handle = CreateRemoteThread(pi.hProcess, NULL, 0,
3085 (LPTHREAD_START_ROUTINE)exit_thread_ptr,
3086 (PVOID)(ULONG_PTR)0x1234, CREATE_SUSPENDED, NULL);
3087 ok(thread_handle != NULL, "Could not create remote thread (%d)\n", GetLastError());
3089 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3090 ok(!ret, "IAT entry resolved prematurely\n");
3092 ctx.ContextFlags = CONTEXT_ALL;
3093 ret = GetThreadContext( thread_handle, &ctx );
3094 ok( ret, "Failed retrieving remote thread context (%d)\n", GetLastError() );
3095 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags );
3096 #ifdef __x86_64__
3097 ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax );
3098 ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx );
3099 ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %lx/%p\n", ctx.Rcx, exit_thread_ptr );
3100 ok( ctx.Rdx == 0x1234, "wrong rdx %lx\n", ctx.Rdx );
3101 ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi );
3102 ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi );
3103 ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp );
3104 ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 );
3105 ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 );
3106 ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 );
3107 ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 );
3108 ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 );
3109 ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 );
3110 ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 );
3111 ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 );
3112 ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp );
3113 ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags );
3114 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr );
3115 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3116 #else
3117 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp );
3118 if (!ctx.Ebp) /* winxp is completely different */
3120 ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx );
3121 ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx );
3122 ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi );
3123 ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi );
3125 ok( ctx.Eax == (ULONG_PTR)exit_thread_ptr, "wrong eax %08x/%p\n", ctx.Eax, exit_thread_ptr );
3126 ok( ctx.Ebx == 0x1234, "wrong ebx %08x\n", ctx.Ebx );
3127 ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3128 "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp );
3129 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags );
3130 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord );
3131 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3132 #endif
3134 ResumeThread( thread_handle );
3135 dret = WaitForSingleObject(thread_handle, 60000);
3136 ok(dret == WAIT_OBJECT_0, "Waiting for remote thread failed (%d)\n", GetLastError());
3137 ret = GetExitCodeThread(thread_handle, &exit_code);
3138 ok(ret, "Failed to retrieve remote thread exit code (%d)\n", GetLastError());
3139 ok(exit_code == 0x1234, "Invalid remote thread exit code\n");
3141 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3142 ok(ret, "EXE IAT entry not resolved\n");
3144 if (thread_handle)
3145 CloseHandle(thread_handle);
3147 TerminateProcess(pi.hProcess, 0);
3148 WaitForSingleObject(pi.hProcess, 10000);
3149 CloseHandle(pi.hProcess);
3150 CloseHandle(pi.hThread);
3153 static void test_SuspendProcessState(void)
3155 struct pipe_params
3157 ULONG pipe_write_buf;
3158 ULONG pipe_read_buf;
3159 ULONG bytes_returned;
3160 CHAR pipe_name[MAX_PATH];
3163 #ifdef __x86_64__
3164 struct remote_rop_chain
3166 void *exit_process_ptr;
3167 ULONG_PTR home_rcx;
3168 ULONG_PTR home_rdx;
3169 ULONG_PTR home_r8;
3170 ULONG_PTR home_r9;
3171 ULONG_PTR pipe_read_buf_size;
3172 ULONG_PTR bytes_returned;
3173 ULONG_PTR timeout;
3175 #else
3176 struct remote_rop_chain
3178 void *exit_process_ptr;
3179 ULONG_PTR pipe_name;
3180 ULONG_PTR pipe_write_buf;
3181 ULONG_PTR pipe_write_buf_size;
3182 ULONG_PTR pipe_read_buf;
3183 ULONG_PTR pipe_read_buf_size;
3184 ULONG_PTR bytes_returned;
3185 ULONG_PTR timeout;
3186 void *unreached_ret;
3187 ULONG_PTR exit_code;
3189 #endif
3191 static const char pipe_name[] = "\\\\.\\pipe\\TestPipe";
3192 static const ULONG pipe_write_magic = 0x454e4957;
3193 STARTUPINFOA si = {0};
3194 PROCESS_INFORMATION pi = {0};
3195 PVOID exe_base, remote_pipe_params, exit_process_ptr,
3196 call_named_pipe_a;
3197 IMAGE_NT_HEADERS nt_header;
3198 struct pipe_params pipe_params;
3199 struct remote_rop_chain rop_chain;
3200 CONTEXT ctx;
3201 HANDLE server_pipe_handle;
3202 BOOL pipe_connected;
3203 ULONG pipe_magic, numb;
3204 BOOL ret;
3205 void *entry_ptr, *peb_ptr;
3206 PEB child_peb;
3208 exit_process_ptr = GetProcAddress(hkernel32, "ExitProcess");
3209 ok(exit_process_ptr != NULL, "GetProcAddress ExitProcess failed\n");
3211 call_named_pipe_a = GetProcAddress(hkernel32, "CallNamedPipeA");
3212 ok(call_named_pipe_a != NULL, "GetProcAddress CallNamedPipeA failed\n");
3214 si.cb = sizeof(si);
3215 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3216 ok(ret, "Failed to create process (%d)\n", GetLastError());
3218 exe_base = get_process_exe(pi.hProcess, &nt_header);
3219 /* Make sure we found the EXE in the new process */
3220 ok(exe_base != NULL, "Could not find EXE in remote process\n");
3222 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3223 ok(!ret, "IAT entry resolved prematurely\n");
3225 server_pipe_handle = CreateNamedPipeA(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH,
3226 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0x20000, 0x20000,
3227 0, NULL);
3228 ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%d)\n", GetLastError());
3230 /* Set up the remote process environment */
3231 ctx.ContextFlags = CONTEXT_ALL;
3232 ret = GetThreadContext(pi.hThread, &ctx);
3233 ok(ret, "Failed retrieving remote thread context (%d)\n", GetLastError());
3234 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags );
3236 remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE);
3237 ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%d)\n", GetLastError());
3239 pipe_params.pipe_write_buf = pipe_write_magic;
3240 pipe_params.pipe_read_buf = 0;
3241 pipe_params.bytes_returned = 0;
3242 strcpy(pipe_params.pipe_name, pipe_name);
3244 ret = WriteProcessMemory(pi.hProcess, remote_pipe_params,
3245 &pipe_params, sizeof(pipe_params), NULL);
3246 ok(ret, "Failed to write to remote process memory (%d)\n", GetLastError());
3248 #ifdef __x86_64__
3249 ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax );
3250 ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx );
3251 ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi );
3252 ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi );
3253 ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp );
3254 ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 );
3255 ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 );
3256 ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 );
3257 ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 );
3258 ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 );
3259 ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 );
3260 ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 );
3261 ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 );
3262 ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp );
3263 ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags );
3264 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr );
3265 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3266 entry_ptr = (void *)ctx.Rcx;
3267 peb_ptr = (void *)ctx.Rdx;
3269 rop_chain.exit_process_ptr = exit_process_ptr;
3270 ctx.Rcx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3271 ctx.Rdx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3272 ctx.R8 = sizeof(pipe_params.pipe_write_buf);
3273 ctx.R9 = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3274 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3275 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3276 rop_chain.timeout = 10000;
3278 ctx.Rip = (ULONG_PTR)call_named_pipe_a;
3279 ctx.Rsp -= sizeof(rop_chain);
3280 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL);
3281 ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3282 #else
3283 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp );
3284 if (!ctx.Ebp) /* winxp is completely different */
3286 ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx );
3287 ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx );
3288 ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi );
3289 ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi );
3291 ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3292 "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp );
3293 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags );
3294 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord );
3295 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3296 entry_ptr = (void *)ctx.Eax;
3297 peb_ptr = (void *)ctx.Ebx;
3299 rop_chain.exit_process_ptr = exit_process_ptr;
3300 rop_chain.pipe_name = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3301 rop_chain.pipe_write_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3302 rop_chain.pipe_write_buf_size = sizeof(pipe_params.pipe_write_buf);
3303 rop_chain.pipe_read_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3304 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3305 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3306 rop_chain.timeout = 10000;
3307 rop_chain.exit_code = 0;
3309 ctx.Eip = (ULONG_PTR)call_named_pipe_a;
3310 ctx.Esp -= sizeof(rop_chain);
3311 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Esp, &rop_chain, sizeof(rop_chain), NULL);
3312 ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3313 #endif
3315 ret = ReadProcessMemory( pi.hProcess, peb_ptr, &child_peb, sizeof(child_peb), NULL );
3316 ok( ret, "Failed to read PEB (%u)\n", GetLastError() );
3317 ok( child_peb.ImageBaseAddress == exe_base, "wrong base %p/%p\n",
3318 child_peb.ImageBaseAddress, exe_base );
3319 ok( entry_ptr == (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint,
3320 "wrong entry point %p/%p\n", entry_ptr,
3321 (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint );
3323 ret = SetThreadContext(pi.hThread, &ctx);
3324 ok(ret, "Failed to set remote thread context (%d)\n", GetLastError());
3326 ResumeThread(pi.hThread);
3328 pipe_connected = ConnectNamedPipe(server_pipe_handle, NULL) || (GetLastError() == ERROR_PIPE_CONNECTED);
3329 ok(pipe_connected, "Pipe did not connect\n");
3331 ret = ReadFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3332 ok(ret, "Failed to read buffer from pipe (%d)\n", GetLastError());
3334 ok(pipe_magic == pipe_write_magic, "Did not get the correct magic from the remote process\n");
3336 /* Validate the Imports, at this point the thread in the new process should have
3337 initialized the EXE module imports and call each dll DllMain notifying it on
3338 the new thread in the process. */
3339 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3340 ok(ret, "EXE IAT is not resolved\n");
3342 ret = WriteFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3343 ok(ret, "Failed to write the magic back to the pipe (%d)\n", GetLastError());
3345 CloseHandle(server_pipe_handle);
3346 TerminateProcess(pi.hProcess, 0);
3347 WaitForSingleObject(pi.hProcess, 10000);
3348 CloseHandle(pi.hProcess);
3349 CloseHandle(pi.hThread);
3351 #else
3352 static void test_SuspendProcessNewThread(void)
3355 static void test_SuspendProcessState(void)
3358 #endif
3360 static void test_DetachStdHandles(void)
3362 #ifndef _WIN64
3363 char buffer[MAX_PATH], tempfile[MAX_PATH];
3364 STARTUPINFOA startup;
3365 PROCESS_INFORMATION info;
3366 HANDLE hstdin, hstdout, hstderr, htemp;
3367 BOOL res;
3369 hstdin = GetStdHandle(STD_INPUT_HANDLE);
3370 hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
3371 hstderr = GetStdHandle(STD_ERROR_HANDLE);
3373 get_file_name(tempfile);
3374 htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3375 ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n");
3377 memset(&startup, 0, sizeof(startup));
3378 startup.cb = sizeof(startup);
3379 startup.dwFlags = STARTF_USESHOWWINDOW;
3380 startup.wShowWindow = SW_SHOWNORMAL;
3381 get_file_name(resfile);
3382 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3384 SetStdHandle(STD_INPUT_HANDLE, htemp);
3385 SetStdHandle(STD_OUTPUT_HANDLE, htemp);
3386 SetStdHandle(STD_ERROR_HANDLE, htemp);
3388 res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3389 &info);
3391 SetStdHandle(STD_INPUT_HANDLE, hstdin);
3392 SetStdHandle(STD_OUTPUT_HANDLE, hstdout);
3393 SetStdHandle(STD_ERROR_HANDLE, hstderr);
3395 ok(res, "CreateProcess failed\n");
3396 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3397 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3398 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3399 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3400 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3401 okChildInt("TEB", "hStdInput", 0);
3402 okChildInt("TEB", "hStdOutput", 0);
3403 okChildInt("TEB", "hStdError", 0);
3404 release_memory();
3405 DeleteFileA(resfile);
3407 CloseHandle(htemp);
3408 DeleteFileA(tempfile);
3409 #endif
3412 static void test_GetNumaProcessorNode(void)
3414 SYSTEM_INFO si;
3415 UCHAR node;
3416 BOOL ret;
3417 int i;
3419 if (!pGetNumaProcessorNode)
3421 win_skip("GetNumaProcessorNode is missing\n");
3422 return;
3425 GetSystemInfo(&si);
3426 for (i = 0; i < 256; i++)
3428 SetLastError(0xdeadbeef);
3429 node = (i < si.dwNumberOfProcessors) ? 0xFF : 0xAA;
3430 ret = pGetNumaProcessorNode(i, &node);
3431 if (i < si.dwNumberOfProcessors)
3433 ok(ret, "GetNumaProcessorNode returned FALSE for processor %d\n", i);
3434 ok(node != 0xFF, "expected node != 0xFF, but got 0xFF\n");
3436 else
3438 ok(!ret, "GetNumaProcessorNode returned TRUE for processor %d\n", i);
3439 ok(node == 0xFF || broken(node == 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node);
3440 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3445 static void test_session_info(void)
3447 DWORD session_id, active_session;
3448 BOOL r;
3450 if (!pProcessIdToSessionId)
3452 win_skip("ProcessIdToSessionId is missing\n");
3453 return;
3456 r = pProcessIdToSessionId(GetCurrentProcessId(), &session_id);
3457 ok(r, "ProcessIdToSessionId failed: %u\n", GetLastError());
3458 trace("session_id = %x\n", session_id);
3460 active_session = pWTSGetActiveConsoleSessionId();
3461 trace("active_session = %x\n", active_session);
3464 static void test_process_info(void)
3466 char buf[4096];
3467 static const ULONG info_size[] =
3469 sizeof(PROCESS_BASIC_INFORMATION) /* ProcessBasicInformation */,
3470 sizeof(QUOTA_LIMITS) /* ProcessQuotaLimits */,
3471 sizeof(IO_COUNTERS) /* ProcessIoCounters */,
3472 sizeof(VM_COUNTERS) /* ProcessVmCounters */,
3473 sizeof(KERNEL_USER_TIMES) /* ProcessTimes */,
3474 sizeof(ULONG) /* ProcessBasePriority */,
3475 sizeof(ULONG) /* ProcessRaisePriority */,
3476 sizeof(HANDLE) /* ProcessDebugPort */,
3477 sizeof(HANDLE) /* ProcessExceptionPort */,
3478 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3479 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3480 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3481 sizeof(ULONG) /* ProcessDefaultHardErrorMode */,
3482 0 /* ProcessIoPortHandlers: kernel-mode only */,
3483 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3484 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3485 sizeof(ULONG) /* ProcessUserModeIOPL */,
3486 sizeof(BOOLEAN) /* ProcessEnableAlignmentFaultFixup */,
3487 sizeof(PROCESS_PRIORITY_CLASS) /* ProcessPriorityClass */,
3488 sizeof(ULONG) /* ProcessWx86Information */,
3489 sizeof(ULONG) /* ProcessHandleCount */,
3490 sizeof(ULONG_PTR) /* ProcessAffinityMask */,
3491 sizeof(ULONG) /* ProcessPriorityBoost */,
3492 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3493 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3494 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3495 sizeof(ULONG_PTR) /* ProcessWow64Information */,
3496 sizeof(buf) /* ProcessImageFileName */,
3497 sizeof(ULONG) /* ProcessLUIDDeviceMapsEnabled */,
3498 sizeof(ULONG) /* ProcessBreakOnTermination */,
3499 sizeof(HANDLE) /* ProcessDebugObjectHandle */,
3500 sizeof(ULONG) /* ProcessDebugFlags */,
3501 sizeof(buf) /* ProcessHandleTracing */,
3502 sizeof(ULONG) /* ProcessIoPriority */,
3503 sizeof(ULONG) /* ProcessExecuteFlags */,
3504 0 /* FIXME: sizeof(?) ProcessTlsInformation */,
3505 0 /* FIXME: sizeof(?) ProcessCookie */,
3506 sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */,
3507 0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */,
3508 sizeof(ULONG) /* ProcessPagePriority */,
3509 40 /* ProcessInstrumentationCallback */,
3510 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
3511 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
3512 sizeof(buf) /* ProcessImageFileNameWin32 */,
3513 #if 0 /* FIXME: Add remaining classes */
3514 sizeof(HANDLE) /* ProcessImageFileMapping */,
3515 sizeof(PROCESS_AFFINITY_UPDATE_MODE) /* ProcessAffinityUpdateMode */,
3516 sizeof(PROCESS_MEMORY_ALLOCATION_MODE) /* ProcessMemoryAllocationMode */,
3517 sizeof(USHORT[]) /* ProcessGroupInformation */,
3518 sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */,
3519 sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */,
3520 sizeof(PROCESS_WINDOW_INFORMATION) /* ProcessWindowInformation */,
3521 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */,
3522 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */,
3523 sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */,
3524 sizeof(?) /* ProcessHandleCheckingMode */,
3525 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION) /* ProcessKeepAliveCount */,
3526 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION) /* ProcessRevokeFileHandles */,
3527 sizeof(PROCESS_WORKING_SET_CONTROL) /* ProcessWorkingSetControl */,
3528 sizeof(?) /* ProcessHandleTable */,
3529 sizeof(?) /* ProcessCheckStackExtentsMode */,
3530 sizeof(buf) /* ProcessCommandLineInformation */,
3531 sizeof(PS_PROTECTION) /* ProcessProtectionInformation */,
3532 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO) /* ProcessMemoryExhaustion */,
3533 sizeof(PROCESS_FAULT_INFORMATION) /* ProcessFaultInformation */,
3534 sizeof(PROCESS_TELEMETRY_ID_INFORMATION) /* ProcessTelemetryIdInformation */,
3535 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION) /* ProcessCommitReleaseInformation */,
3536 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3537 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3538 0 /* ProcessReserved1Information */,
3539 0 /* ProcessReserved2Information */,
3540 sizeof(?) /* ProcessSubsystemProcess */,
3541 sizeof(PROCESS_JOB_MEMORY_INFO) /* ProcessJobMemoryInformation */,
3542 #endif
3544 HANDLE hproc;
3545 ULONG i, status, ret_len, size;
3547 if (!pNtQueryInformationProcess)
3549 win_skip("NtQueryInformationProcess is not available on this platform\n");
3550 return;
3553 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
3554 if (!hproc)
3556 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
3557 return;
3560 for (i = 0; i < MaxProcessInfoClass; i++)
3562 size = info_size[i];
3563 if (!size) size = sizeof(buf);
3564 ret_len = 0;
3565 status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len);
3566 if (status == STATUS_NOT_IMPLEMENTED) continue;
3567 if (status == STATUS_INVALID_INFO_CLASS) continue;
3568 if (status == STATUS_INFO_LENGTH_MISMATCH) continue;
3570 switch (i)
3572 case ProcessBasicInformation:
3573 case ProcessQuotaLimits:
3574 case ProcessTimes:
3575 case ProcessPriorityClass:
3576 case ProcessPriorityBoost:
3577 case ProcessLUIDDeviceMapsEnabled:
3578 case 33 /* ProcessIoPriority */:
3579 case ProcessIoCounters:
3580 case ProcessVmCounters:
3581 case ProcessWow64Information:
3582 case ProcessDefaultHardErrorMode:
3583 case ProcessHandleCount:
3584 case ProcessImageFileName:
3585 case ProcessImageInformation:
3586 case ProcessPagePriority:
3587 case ProcessImageFileNameWin32:
3588 ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3589 break;
3591 case ProcessAffinityMask:
3592 case ProcessBreakOnTermination:
3593 ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */,
3594 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3595 break;
3597 case ProcessDebugObjectHandle:
3598 ok(status == STATUS_ACCESS_DENIED || status == STATUS_PORT_NOT_SET,
3599 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3600 break;
3602 case ProcessExecuteFlags:
3603 case ProcessDebugPort:
3604 case ProcessDebugFlags:
3605 case ProcessCookie:
3606 todo_wine
3607 ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3608 break;
3610 default:
3611 ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3612 break;
3616 CloseHandle(hproc);
3619 static void test_GetLogicalProcessorInformationEx(void)
3621 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info;
3622 DWORD len;
3623 BOOL ret;
3625 if (!pGetLogicalProcessorInformationEx)
3627 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3628 return;
3631 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, NULL);
3632 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
3634 len = 0;
3635 ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len);
3636 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3637 ok(len > 0, "got %u\n", len);
3639 len = 0;
3640 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len);
3641 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3642 ok(len > 0, "got %u\n", len);
3644 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
3645 ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len);
3646 ok(ret, "got %d, error %d\n", ret, GetLastError());
3647 ok(info->Size > 0, "got %u\n", info->Size);
3648 HeapFree(GetProcessHeap(), 0, info);
3651 static void test_largepages(void)
3653 SIZE_T size;
3655 if (!pGetLargePageMinimum) {
3656 skip("No GetLargePageMinimum support.\n");
3657 return;
3659 size = pGetLargePageMinimum();
3661 ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size);
3664 struct proc_thread_attr
3666 DWORD_PTR attr;
3667 SIZE_T size;
3668 void *value;
3671 struct _PROC_THREAD_ATTRIBUTE_LIST
3673 DWORD mask; /* bitmask of items in list */
3674 DWORD size; /* max number of items in list */
3675 DWORD count; /* number of items in list */
3676 DWORD pad;
3677 DWORD_PTR unk;
3678 struct proc_thread_attr attrs[10];
3681 static void test_ProcThreadAttributeList(void)
3683 BOOL ret;
3684 SIZE_T size, needed;
3685 int i;
3686 struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list;
3687 HANDLE handles[4];
3689 if (!pInitializeProcThreadAttributeList)
3691 win_skip("No support for ProcThreadAttributeList\n");
3692 return;
3695 for (i = 0; i <= 10; i++)
3697 needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[i]);
3698 ret = pInitializeProcThreadAttributeList(NULL, i, 0, &size);
3699 ok(!ret, "got %d\n", ret);
3700 if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */
3701 break;
3702 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
3703 ok(size == needed, "%d: got %ld expect %ld\n", i, size, needed);
3705 memset(&list, 0xcc, sizeof(list));
3706 ret = pInitializeProcThreadAttributeList(&list, i, 0, &size);
3707 ok(ret, "got %d\n", ret);
3708 ok(list.mask == 0, "%d: got %08x\n", i, list.mask);
3709 ok(list.size == i, "%d: got %08x\n", i, list.size);
3710 ok(list.count == 0, "%d: got %08x\n", i, list.count);
3711 ok(list.unk == 0, "%d: got %08lx\n", i, list.unk);
3714 memset(handles, 0, sizeof(handles));
3715 memset(&expect_list, 0xcc, sizeof(expect_list));
3716 expect_list.mask = 0;
3717 expect_list.size = i - 1;
3718 expect_list.count = 0;
3719 expect_list.unk = 0;
3721 ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3722 ok(!ret, "got %d\n", ret);
3723 ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %d\n", GetLastError());
3725 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL);
3726 ok(!ret, "got %d\n", ret);
3727 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3729 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL);
3730 ok(!ret, "got %d\n", ret);
3731 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3733 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3734 ok(ret, "got %d\n", ret);
3736 expect_list.mask |= 1 << ProcThreadAttributeParentProcess;
3737 expect_list.attrs[0].attr = PROC_THREAD_ATTRIBUTE_PARENT_PROCESS;
3738 expect_list.attrs[0].size = sizeof(handles[0]);
3739 expect_list.attrs[0].value = handles;
3740 expect_list.count++;
3742 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3743 ok(!ret, "got %d\n", ret);
3744 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3746 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL);
3747 ok(!ret, "got %d\n", ret);
3748 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3750 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3751 ok(ret, "got %d\n", ret);
3753 expect_list.mask |= 1 << ProcThreadAttributeHandleList;
3754 expect_list.attrs[1].attr = PROC_THREAD_ATTRIBUTE_HANDLE_LIST;
3755 expect_list.attrs[1].size = sizeof(handles);
3756 expect_list.attrs[1].value = handles;
3757 expect_list.count++;
3759 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3760 ok(!ret, "got %d\n", ret);
3761 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3763 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3764 ok(ret || GetLastError() == ERROR_NOT_SUPPORTED, "got %d gle %d\n", ret, GetLastError());
3766 if (ret)
3768 expect_list.mask |= 1 << ProcThreadAttributeIdealProcessor;
3769 expect_list.attrs[2].attr = PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR;
3770 expect_list.attrs[2].size = sizeof(PROCESSOR_NUMBER);
3771 expect_list.attrs[2].value = handles;
3772 expect_list.count++;
3775 ok(!memcmp(&list, &expect_list, size), "mismatch\n");
3777 pDeleteProcThreadAttributeList(&list);
3780 START_TEST(process)
3782 HANDLE job;
3783 BOOL b = init();
3784 ok(b, "Basic init of CreateProcess test\n");
3785 if (!b) return;
3787 if (myARGC >= 3)
3789 if (!strcmp(myARGV[2], "dump") && myARGC >= 4)
3791 doChild(myARGV[3], (myARGC >= 5) ? myARGV[4] : NULL);
3792 return;
3794 else if (!strcmp(myARGV[2], "wait"))
3796 Sleep(30000);
3797 ok(0, "Child process not killed\n");
3798 return;
3800 else if (!strcmp(myARGV[2], "exit"))
3802 Sleep(100);
3803 return;
3805 else if (!strcmp(myARGV[2], "nested") && myARGC >= 4)
3807 char buffer[MAX_PATH];
3808 STARTUPINFOA startup;
3809 PROCESS_INFORMATION info;
3811 memset(&startup, 0, sizeof(startup));
3812 startup.cb = sizeof(startup);
3813 startup.dwFlags = STARTF_USESHOWWINDOW;
3814 startup.wShowWindow = SW_SHOWNORMAL;
3816 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, myARGV[3]);
3817 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n");
3818 CloseHandle(info.hProcess);
3819 CloseHandle(info.hThread);
3820 return;
3823 ok(0, "Unexpected command %s\n", myARGV[2]);
3824 return;
3827 test_process_info();
3828 test_TerminateProcess();
3829 test_Startup();
3830 test_CommandLine();
3831 test_Directory();
3832 test_Toolhelp();
3833 test_Environment();
3834 test_SuspendFlag();
3835 test_DebuggingFlag();
3836 test_Console();
3837 test_ExitCode();
3838 test_OpenProcess();
3839 test_GetProcessVersion();
3840 test_GetProcessImageFileNameA();
3841 test_QueryFullProcessImageNameA();
3842 test_QueryFullProcessImageNameW();
3843 test_Handles();
3844 test_IsWow64Process();
3845 test_SystemInfo();
3846 test_RegistryQuota();
3847 test_DuplicateHandle();
3848 test_StartupNoConsole();
3849 test_DetachConsoleHandles();
3850 test_DetachStdHandles();
3851 test_GetNumaProcessorNode();
3852 test_session_info();
3853 test_GetLogicalProcessorInformationEx();
3854 test_largepages();
3855 test_ProcThreadAttributeList();
3856 test_SuspendProcessState();
3857 test_SuspendProcessNewThread();
3859 /* things that can be tested:
3860 * lookup: check the way program to be executed is searched
3861 * handles: check the handle inheritance stuff (+sec options)
3862 * console: check if console creation parameters work
3865 if (!pCreateJobObjectW)
3867 win_skip("No job object support\n");
3868 return;
3871 test_IsProcessInJob();
3872 test_TerminateJobObject();
3873 test_QueryInformationJobObject();
3874 test_CompletionPort();
3875 test_KillOnJobClose();
3876 test_WaitForJobObject();
3877 job = test_AddSelfToJob();
3878 test_jobInheritance(job);
3879 test_BreakawayOk(job);
3880 CloseHandle(job);