Remove unnecessary executable bits
[reactos.git] / modules / rostests / winetests / kernel32 / process.c
1 /*
2 * Unit test suite for process functions
3 *
4 * Copyright 2002 Eric Pouech
5 * Copyright 2006 Dmitry Timoshkov
6 * Copyright 2014 Michael Müller
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "wincon.h"
34 #include "winnls.h"
35 #include "winternl.h"
36 #include "tlhelp32.h"
37
38 #include "wine/test.h"
39
40 #include "winnt.h"
41
42 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
43 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
44 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
45 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
46
47 #define expect_eq_d(expected, actual) \
48 do { \
49 int value = (actual); \
50 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
51 (expected), value); \
52 } while (0)
53 #define expect_eq_s(expected, actual) \
54 do { \
55 LPCSTR value = (actual); \
56 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
57 expected, value); \
58 } while (0)
59 #define expect_eq_ws_i(expected, actual) \
60 do { \
61 LPCWSTR value = (actual); \
62 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
63 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
64 } while (0)
65
66 static HINSTANCE hkernel32, hntdll;
67 static void (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO);
68 static BOOL (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD);
69 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
70 static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
71 static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
72 static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize);
73 static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize);
74 static DWORD (WINAPI *pK32GetProcessImageFileNameA)(HANDLE,LPSTR,DWORD);
75 static HANDLE (WINAPI *pCreateJobObjectW)(LPSECURITY_ATTRIBUTES sa, LPCWSTR name);
76 static BOOL (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process);
77 static BOOL (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result);
78 static BOOL (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code);
79 static BOOL (WINAPI *pQueryInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len, LPDWORD ret_len);
80 static BOOL (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len);
81 static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads);
82 static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR);
83 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
84 static BOOL (WINAPI *pProcessIdToSessionId)(DWORD,DWORD*);
85 static DWORD (WINAPI *pWTSGetActiveConsoleSessionId)(void);
86 static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
87 static BOOL (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*);
88 static BOOL (WINAPI *pProcess32Next)(HANDLE, PROCESSENTRY32*);
89 static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*);
90 static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*);
91 static BOOL (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
92 static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
93 static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
94 static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
95 static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
96 static DWORD (WINAPI *pGetActiveProcessorCount)(WORD);
97
98 /* ############################### */
99 static char base[MAX_PATH];
100 static char selfname[MAX_PATH];
101 static char* exename;
102 static char resfile[MAX_PATH];
103
104 static int myARGC;
105 static char** myARGV;
106
107 /* As some environment variables get very long on Unix, we only test for
108 * the first 127 bytes.
109 * Note that increasing this value past 256 may exceed the buffer size
110 * limitations of the *Profile functions (at least on Wine).
111 */
112 #define MAX_LISTED_ENV_VAR 128
113
114 /* ---------------- portable memory allocation thingie */
115
116 static char memory[1024*256];
117 static char* memory_index = memory;
118
119 static char* grab_memory(size_t len)
120 {
121 char* ret = memory_index;
122 /* align on dword */
123 len = (len + 3) & ~3;
124 memory_index += len;
125 assert(memory_index <= memory + sizeof(memory));
126 return ret;
127 }
128
129 static void release_memory(void)
130 {
131 memory_index = memory;
132 }
133
134 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
135
136 static const char* encodeA(const char* str)
137 {
138 char* ptr;
139 size_t len,i;
140
141 if (!str) return "";
142 len = strlen(str) + 1;
143 ptr = grab_memory(len * 2 + 1);
144 for (i = 0; i < len; i++)
145 sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
146 ptr[2 * len] = '\0';
147 return ptr;
148 }
149
150 static const char* encodeW(const WCHAR* str)
151 {
152 char* ptr;
153 size_t len,i;
154
155 if (!str) return "";
156 len = lstrlenW(str) + 1;
157 ptr = grab_memory(len * 4 + 1);
158 assert(ptr);
159 for (i = 0; i < len; i++)
160 sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
161 ptr[4 * len] = '\0';
162 return ptr;
163 }
164
165 static unsigned decode_char(char c)
166 {
167 if (c >= '0' && c <= '9') return c - '0';
168 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
169 assert(c >= 'A' && c <= 'F');
170 return c - 'A' + 10;
171 }
172
173 static char* decodeA(const char* str)
174 {
175 char* ptr;
176 size_t len,i;
177
178 len = strlen(str) / 2;
179 if (!len--) return NULL;
180 ptr = grab_memory(len + 1);
181 for (i = 0; i < len; i++)
182 ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
183 ptr[len] = '\0';
184 return ptr;
185 }
186
187 /* This will be needed to decode Unicode strings saved by the child process
188 * when we test Unicode functions.
189 */
190 static WCHAR* decodeW(const char* str)
191 {
192 size_t len;
193 WCHAR* ptr;
194 int i;
195
196 len = strlen(str) / 4;
197 if (!len--) return NULL;
198 ptr = (WCHAR*)grab_memory(len * 2 + 1);
199 for (i = 0; i < len; i++)
200 ptr[i] = (decode_char(str[4 * i]) << 12) |
201 (decode_char(str[4 * i + 1]) << 8) |
202 (decode_char(str[4 * i + 2]) << 4) |
203 (decode_char(str[4 * i + 3]) << 0);
204 ptr[len] = '\0';
205 return ptr;
206 }
207
208 /******************************************************************
209 * init
210 *
211 * generates basic information like:
212 * base: absolute path to curr dir
213 * selfname: the way to reinvoke ourselves
214 * exename: executable without the path
215 * function-pointers, which are not implemented in all windows versions
216 */
217 static BOOL init(void)
218 {
219 char *p;
220
221 myARGC = winetest_get_mainargs( &myARGV );
222 if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
223 strcpy(selfname, myARGV[0]);
224
225 /* Strip the path of selfname */
226 if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1;
227 else exename = selfname;
228
229 if ((p = strrchr(exename, '/')) != NULL) exename = p + 1;
230
231 hkernel32 = GetModuleHandleA("kernel32");
232 hntdll = GetModuleHandleA("ntdll.dll");
233
234 pNtQueryInformationProcess = (void *)GetProcAddress(hntdll, "NtQueryInformationProcess");
235
236 pGetNativeSystemInfo = (void *) GetProcAddress(hkernel32, "GetNativeSystemInfo");
237 pGetSystemRegistryQuota = (void *) GetProcAddress(hkernel32, "GetSystemRegistryQuota");
238 pIsWow64Process = (void *) GetProcAddress(hkernel32, "IsWow64Process");
239 pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
240 pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
241 pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA");
242 pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW");
243 pK32GetProcessImageFileNameA = (void *) GetProcAddress(hkernel32, "K32GetProcessImageFileNameA");
244 pCreateJobObjectW = (void *)GetProcAddress(hkernel32, "CreateJobObjectW");
245 pAssignProcessToJobObject = (void *)GetProcAddress(hkernel32, "AssignProcessToJobObject");
246 pIsProcessInJob = (void *)GetProcAddress(hkernel32, "IsProcessInJob");
247 pTerminateJobObject = (void *)GetProcAddress(hkernel32, "TerminateJobObject");
248 pQueryInformationJobObject = (void *)GetProcAddress(hkernel32, "QueryInformationJobObject");
249 pSetInformationJobObject = (void *)GetProcAddress(hkernel32, "SetInformationJobObject");
250 pCreateIoCompletionPort = (void *)GetProcAddress(hkernel32, "CreateIoCompletionPort");
251 pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode");
252 pProcessIdToSessionId = (void *)GetProcAddress(hkernel32, "ProcessIdToSessionId");
253 pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId");
254 pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
255 pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First");
256 pProcess32Next = (void *)GetProcAddress(hkernel32, "Process32Next");
257 pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First");
258 pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next");
259 pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
260 pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum");
261 pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
262 pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
263 pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
264 pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount");
265
266 return TRUE;
267 }
268
269 /******************************************************************
270 * get_file_name
271 *
272 * generates an absolute file_name for temporary file
273 *
274 */
275 static void get_file_name(char* buf)
276 {
277 char path[MAX_PATH];
278
279 buf[0] = '\0';
280 GetTempPathA(sizeof(path), path);
281 GetTempFileNameA(path, "wt", 0, buf);
282 }
283
284 /******************************************************************
285 * static void childPrintf
286 *
287 */
288 static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...)
289 {
290 va_list valist;
291 char buffer[1024+4*MAX_LISTED_ENV_VAR];
292 DWORD w;
293
294 va_start(valist, fmt);
295 vsprintf(buffer, fmt, valist);
296 va_end(valist);
297 WriteFile(h, buffer, strlen(buffer), &w, NULL);
298 }
299
300
301 /******************************************************************
302 * doChild
303 *
304 * output most of the information in the child process
305 */
306 static void doChild(const char* file, const char* option)
307 {
308 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
309 STARTUPINFOA siA;
310 STARTUPINFOW siW;
311 int i;
312 char *ptrA, *ptrA_save;
313 WCHAR *ptrW, *ptrW_save;
314 char bufA[MAX_PATH];
315 WCHAR bufW[MAX_PATH];
316 HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
317 HANDLE snapshot;
318 PROCESSENTRY32 pe;
319 BOOL ret;
320
321 if (hFile == INVALID_HANDLE_VALUE) return;
322
323 /* output of startup info (Ansi) */
324 GetStartupInfoA(&siA);
325 childPrintf(hFile,
326 "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
327 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
328 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
329 "dwFlags=%u\nwShowWindow=%u\n"
330 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
331 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
332 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize,
333 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute,
334 siA.dwFlags, siA.wShowWindow,
335 (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError);
336
337 /* check the console handles in the TEB */
338 childPrintf(hFile, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
339 (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput,
340 (DWORD_PTR)params->hStdError);
341
342 /* since GetStartupInfoW is only implemented in win2k,
343 * zero out before calling so we can notice the difference
344 */
345 memset(&siW, 0, sizeof(siW));
346 GetStartupInfoW(&siW);
347 childPrintf(hFile,
348 "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
349 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
350 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
351 "dwFlags=%u\nwShowWindow=%u\n"
352 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
353 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
354 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize,
355 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute,
356 siW.dwFlags, siW.wShowWindow,
357 (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError);
358
359 /* Arguments */
360 childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
361 for (i = 0; i < myARGC; i++)
362 {
363 childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
364 }
365 childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
366 childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
367
368 /* output toolhelp information */
369 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
370 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
371 memset(&pe, 0, sizeof(pe));
372 pe.dwSize = sizeof(pe);
373 if (pProcess32First(snapshot, &pe))
374 {
375 while (pe.th32ProcessID != GetCurrentProcessId())
376 if (!pProcess32Next(snapshot, &pe)) break;
377 }
378 CloseHandle(snapshot);
379 ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n");
380 childPrintf(hFile,
381 "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n"
382 "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n"
383 "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n",
384 pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID,
385 pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase,
386 pe.dwFlags, encodeA(pe.szExeFile));
387
388 /* output of environment (Ansi) */
389 ptrA_save = ptrA = GetEnvironmentStringsA();
390 if (ptrA)
391 {
392 char env_var[MAX_LISTED_ENV_VAR];
393
394 childPrintf(hFile, "[EnvironmentA]\n");
395 i = 0;
396 while (*ptrA)
397 {
398 lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR);
399 childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
400 i++;
401 ptrA += strlen(ptrA) + 1;
402 }
403 childPrintf(hFile, "len=%d\n\n", i);
404 FreeEnvironmentStringsA(ptrA_save);
405 }
406
407 /* output of environment (Unicode) */
408 ptrW_save = ptrW = GetEnvironmentStringsW();
409 if (ptrW)
410 {
411 WCHAR env_var[MAX_LISTED_ENV_VAR];
412
413 childPrintf(hFile, "[EnvironmentW]\n");
414 i = 0;
415 while (*ptrW)
416 {
417 lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1);
418 env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
419 childPrintf(hFile, "env%d=%s\n", i, encodeW(env_var));
420 i++;
421 ptrW += lstrlenW(ptrW) + 1;
422 }
423 childPrintf(hFile, "len=%d\n\n", i);
424 FreeEnvironmentStringsW(ptrW_save);
425 }
426
427 childPrintf(hFile, "[Misc]\n");
428 if (GetCurrentDirectoryA(sizeof(bufA), bufA))
429 childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
430 if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW))
431 childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
432 childPrintf(hFile, "\n");
433
434 if (option && strcmp(option, "console") == 0)
435 {
436 CONSOLE_SCREEN_BUFFER_INFO sbi;
437 HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE);
438 HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
439 DWORD modeIn, modeOut;
440
441 childPrintf(hFile, "[Console]\n");
442 if (GetConsoleScreenBufferInfo(hConOut, &sbi))
443 {
444 childPrintf(hFile, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
445 sbi.dwSize.X, sbi.dwSize.Y, sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y, sbi.wAttributes);
446 childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
447 sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom);
448 childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n",
449 sbi.dwMaximumWindowSize.X, sbi.dwMaximumWindowSize.Y);
450 }
451 childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
452 GetConsoleCP(), GetConsoleOutputCP());
453 if (GetConsoleMode(hConIn, &modeIn))
454 childPrintf(hFile, "InputMode=%u\n", modeIn);
455 if (GetConsoleMode(hConOut, &modeOut))
456 childPrintf(hFile, "OutputMode=%u\n", modeOut);
457
458 /* now that we have written all relevant information, let's change it */
459 SetLastError(0xdeadbeef);
460 ret = SetConsoleCP(1252);
461 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
462 {
463 win_skip("Setting the codepage is not implemented\n");
464 }
465 else
466 {
467 ok(ret, "Setting CP\n");
468 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
469 }
470
471 ret = SetConsoleMode(hConIn, modeIn ^ 1);
472 ok( ret, "Setting mode (%d)\n", GetLastError());
473 ret = SetConsoleMode(hConOut, modeOut ^ 1);
474 ok( ret, "Setting mode (%d)\n", GetLastError());
475 sbi.dwCursorPosition.X ^= 1;
476 sbi.dwCursorPosition.Y ^= 1;
477 ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition);
478 ok( ret, "Setting cursor position (%d)\n", GetLastError());
479 }
480 if (option && strcmp(option, "stdhandle") == 0)
481 {
482 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
483 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
484
485 if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE)
486 {
487 char buf[1024];
488 DWORD r, w;
489
490 ok(ReadFile(hStdIn, buf, sizeof(buf), &r, NULL) && r > 0, "Reading message from input pipe\n");
491 childPrintf(hFile, "[StdHandle]\nmsg=%s\n\n", encodeA(buf));
492 ok(WriteFile(hStdOut, buf, r, &w, NULL) && w == r, "Writing message to output pipe\n");
493 }
494 }
495
496 if (option && strcmp(option, "exit_code") == 0)
497 {
498 childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123);
499 CloseHandle(hFile);
500 ExitProcess(123);
501 }
502
503 CloseHandle(hFile);
504 }
505
506 static char* getChildString(const char* sect, const char* key)
507 {
508 char buf[1024+4*MAX_LISTED_ENV_VAR];
509 char* ret;
510
511 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
512 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
513 assert(!(strlen(buf) & 1));
514 ret = decodeA(buf);
515 return ret;
516 }
517
518 static WCHAR* getChildStringW(const char* sect, const char* key)
519 {
520 char buf[1024+4*MAX_LISTED_ENV_VAR];
521 WCHAR* ret;
522
523 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
524 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
525 assert(!(strlen(buf) & 1));
526 ret = decodeW(buf);
527 return ret;
528 }
529
530 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
531 * others... (windows uses stricmp while Un*x uses strcasecmp...)
532 */
533 static int wtstrcasecmp(const char* p1, const char* p2)
534 {
535 char c1, c2;
536
537 c1 = c2 = '@';
538 while (c1 == c2 && c1)
539 {
540 c1 = *p1++; c2 = *p2++;
541 if (c1 != c2)
542 {
543 c1 = toupper(c1); c2 = toupper(c2);
544 }
545 }
546 return c1 - c2;
547 }
548
549 static int strCmp(const char* s1, const char* s2, BOOL sensitive)
550 {
551 if (!s1 && !s2) return 0;
552 if (!s2) return -1;
553 if (!s1) return 1;
554 return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2);
555 }
556
557 static void ok_child_string( int line, const char *sect, const char *key,
558 const char *expect, int sensitive )
559 {
560 char* result = getChildString( sect, key );
561 ok_(__FILE__, line)( strCmp(result, expect, sensitive) == 0, "%s:%s expected '%s', got '%s'\n",
562 sect, key, expect ? expect : "(null)", result );
563 }
564
565 static void ok_child_stringWA( int line, const char *sect, const char *key,
566 const char *expect, int sensitive )
567 {
568 WCHAR* expectW;
569 CHAR* resultA;
570 DWORD len;
571 WCHAR* result = getChildStringW( sect, key );
572
573 len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0);
574 expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
575 MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len);
576
577 len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL);
578 resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR));
579 WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL);
580
581 if (sensitive)
582 ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
583 sect, key, expect ? expect : "(null)", resultA );
584 else
585 ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
586 sect, key, expect ? expect : "(null)", resultA );
587 HeapFree(GetProcessHeap(),0,expectW);
588 HeapFree(GetProcessHeap(),0,resultA);
589 }
590
591 static void ok_child_int( int line, const char *sect, const char *key, UINT expect )
592 {
593 UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile );
594 ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result );
595 }
596
597 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
598 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
599 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
600 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
601
602 static void test_Startup(void)
603 {
604 char buffer[MAX_PATH];
605 PROCESS_INFORMATION info;
606 STARTUPINFOA startup,si;
607 char *result;
608 static CHAR title[] = "I'm the title string",
609 desktop[] = "winsta0\\default",
610 empty[] = "";
611
612 /* let's start simplistic */
613 memset(&startup, 0, sizeof(startup));
614 startup.cb = sizeof(startup);
615 startup.dwFlags = STARTF_USESHOWWINDOW;
616 startup.wShowWindow = SW_SHOWNORMAL;
617
618 get_file_name(resfile);
619 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
620 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
621 /* wait for child to terminate */
622 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
623 /* child process has changed result file, so let profile functions know about it */
624 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
625 CloseHandle(info.hThread);
626 CloseHandle(info.hProcess);
627
628 GetStartupInfoA(&si);
629 okChildInt("StartupInfoA", "cb", startup.cb);
630 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
631 okChildInt("StartupInfoA", "dwX", startup.dwX);
632 okChildInt("StartupInfoA", "dwY", startup.dwY);
633 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
634 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
635 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
636 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
637 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
638 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
639 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
640 release_memory();
641 DeleteFileA(resfile);
642
643 /* not so simplistic now */
644 memset(&startup, 0, sizeof(startup));
645 startup.cb = sizeof(startup);
646 startup.dwFlags = STARTF_USESHOWWINDOW;
647 startup.wShowWindow = SW_SHOWNORMAL;
648 startup.lpTitle = title;
649 startup.lpDesktop = desktop;
650 startup.dwXCountChars = 0x12121212;
651 startup.dwYCountChars = 0x23232323;
652 startup.dwX = 0x34343434;
653 startup.dwY = 0x45454545;
654 startup.dwXSize = 0x56565656;
655 startup.dwYSize = 0x67676767;
656 startup.dwFillAttribute = 0xA55A;
657
658 get_file_name(resfile);
659 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
660 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
661 /* wait for child to terminate */
662 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
663 /* child process has changed result file, so let profile functions know about it */
664 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
665 CloseHandle(info.hThread);
666 CloseHandle(info.hProcess);
667
668 okChildInt("StartupInfoA", "cb", startup.cb);
669 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
670 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
671 okChildInt("StartupInfoA", "dwX", startup.dwX);
672 okChildInt("StartupInfoA", "dwY", startup.dwY);
673 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
674 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
675 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
676 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
677 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
678 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
679 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
680 release_memory();
681 DeleteFileA(resfile);
682
683 /* not so simplistic now */
684 memset(&startup, 0, sizeof(startup));
685 startup.cb = sizeof(startup);
686 startup.dwFlags = STARTF_USESHOWWINDOW;
687 startup.wShowWindow = SW_SHOWNORMAL;
688 startup.lpTitle = title;
689 startup.lpDesktop = NULL;
690 startup.dwXCountChars = 0x12121212;
691 startup.dwYCountChars = 0x23232323;
692 startup.dwX = 0x34343434;
693 startup.dwY = 0x45454545;
694 startup.dwXSize = 0x56565656;
695 startup.dwYSize = 0x67676767;
696 startup.dwFillAttribute = 0xA55A;
697
698 get_file_name(resfile);
699 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
700 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
701 /* wait for child to terminate */
702 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
703 /* child process has changed result file, so let profile functions know about it */
704 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
705 CloseHandle(info.hThread);
706 CloseHandle(info.hProcess);
707
708 okChildInt("StartupInfoA", "cb", startup.cb);
709 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
710 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
711 okChildInt("StartupInfoA", "dwX", startup.dwX);
712 okChildInt("StartupInfoA", "dwY", startup.dwY);
713 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
714 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
715 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
716 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
717 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
718 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
719 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
720 release_memory();
721 DeleteFileA(resfile);
722
723 /* not so simplistic now */
724 memset(&startup, 0, sizeof(startup));
725 startup.cb = sizeof(startup);
726 startup.dwFlags = STARTF_USESHOWWINDOW;
727 startup.wShowWindow = SW_SHOWNORMAL;
728 startup.lpTitle = title;
729 startup.lpDesktop = empty;
730 startup.dwXCountChars = 0x12121212;
731 startup.dwYCountChars = 0x23232323;
732 startup.dwX = 0x34343434;
733 startup.dwY = 0x45454545;
734 startup.dwXSize = 0x56565656;
735 startup.dwYSize = 0x67676767;
736 startup.dwFillAttribute = 0xA55A;
737
738 get_file_name(resfile);
739 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
740 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
741 /* wait for child to terminate */
742 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
743 /* child process has changed result file, so let profile functions know about it */
744 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
745 CloseHandle(info.hThread);
746 CloseHandle(info.hProcess);
747
748 okChildInt("StartupInfoA", "cb", startup.cb);
749 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
750 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
751 okChildInt("StartupInfoA", "dwX", startup.dwX);
752 okChildInt("StartupInfoA", "dwY", startup.dwY);
753 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
754 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
755 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
756 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
757 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
758 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
759 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
760 release_memory();
761 DeleteFileA(resfile);
762
763 /* not so simplistic now */
764 memset(&startup, 0, sizeof(startup));
765 startup.cb = sizeof(startup);
766 startup.dwFlags = STARTF_USESHOWWINDOW;
767 startup.wShowWindow = SW_SHOWNORMAL;
768 startup.lpTitle = NULL;
769 startup.lpDesktop = desktop;
770 startup.dwXCountChars = 0x12121212;
771 startup.dwYCountChars = 0x23232323;
772 startup.dwX = 0x34343434;
773 startup.dwY = 0x45454545;
774 startup.dwXSize = 0x56565656;
775 startup.dwYSize = 0x67676767;
776 startup.dwFillAttribute = 0xA55A;
777
778 get_file_name(resfile);
779 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
780 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
781 /* wait for child to terminate */
782 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
783 /* child process has changed result file, so let profile functions know about it */
784 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
785 CloseHandle(info.hThread);
786 CloseHandle(info.hProcess);
787
788 okChildInt("StartupInfoA", "cb", startup.cb);
789 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
790 result = getChildString( "StartupInfoA", "lpTitle" );
791 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
792 "expected '%s' or null, got '%s'\n", selfname, result );
793 okChildInt("StartupInfoA", "dwX", startup.dwX);
794 okChildInt("StartupInfoA", "dwY", startup.dwY);
795 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
796 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
797 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
798 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
799 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
800 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
801 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
802 release_memory();
803 DeleteFileA(resfile);
804
805 /* not so simplistic now */
806 memset(&startup, 0, sizeof(startup));
807 startup.cb = sizeof(startup);
808 startup.dwFlags = STARTF_USESHOWWINDOW;
809 startup.wShowWindow = SW_SHOWNORMAL;
810 startup.lpTitle = empty;
811 startup.lpDesktop = desktop;
812 startup.dwXCountChars = 0x12121212;
813 startup.dwYCountChars = 0x23232323;
814 startup.dwX = 0x34343434;
815 startup.dwY = 0x45454545;
816 startup.dwXSize = 0x56565656;
817 startup.dwYSize = 0x67676767;
818 startup.dwFillAttribute = 0xA55A;
819
820 get_file_name(resfile);
821 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
822 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
823 /* wait for child to terminate */
824 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
825 /* child process has changed result file, so let profile functions know about it */
826 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
827 CloseHandle(info.hThread);
828 CloseHandle(info.hProcess);
829
830 okChildInt("StartupInfoA", "cb", startup.cb);
831 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
832 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
833 okChildInt("StartupInfoA", "dwX", startup.dwX);
834 okChildInt("StartupInfoA", "dwY", startup.dwY);
835 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
836 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
837 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
838 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
839 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
840 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
841 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
842 release_memory();
843 DeleteFileA(resfile);
844
845 /* not so simplistic now */
846 memset(&startup, 0, sizeof(startup));
847 startup.cb = sizeof(startup);
848 startup.dwFlags = STARTF_USESHOWWINDOW;
849 startup.wShowWindow = SW_SHOWNORMAL;
850 startup.lpTitle = empty;
851 startup.lpDesktop = empty;
852 startup.dwXCountChars = 0x12121212;
853 startup.dwYCountChars = 0x23232323;
854 startup.dwX = 0x34343434;
855 startup.dwY = 0x45454545;
856 startup.dwXSize = 0x56565656;
857 startup.dwYSize = 0x67676767;
858 startup.dwFillAttribute = 0xA55A;
859
860 get_file_name(resfile);
861 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
862 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
863 /* wait for child to terminate */
864 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
865 /* child process has changed result file, so let profile functions know about it */
866 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
867 CloseHandle(info.hThread);
868 CloseHandle(info.hProcess);
869
870 okChildInt("StartupInfoA", "cb", startup.cb);
871 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
872 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
873 okChildInt("StartupInfoA", "dwX", startup.dwX);
874 okChildInt("StartupInfoA", "dwY", startup.dwY);
875 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
876 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
877 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
878 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
879 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
880 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
881 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
882 release_memory();
883 DeleteFileA(resfile);
884
885 /* TODO: test for A/W and W/A and W/W */
886 }
887
888 static void test_CommandLine(void)
889 {
890 char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
891 char buffer2[MAX_PATH];
892 PROCESS_INFORMATION info;
893 STARTUPINFOA startup;
894 BOOL ret;
895
896 memset(&startup, 0, sizeof(startup));
897 startup.cb = sizeof(startup);
898 startup.dwFlags = STARTF_USESHOWWINDOW;
899 startup.wShowWindow = SW_SHOWNORMAL;
900
901 /* the basics */
902 get_file_name(resfile);
903 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
904 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
905 /* wait for child to terminate */
906 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
907 /* child process has changed result file, so let profile functions know about it */
908 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
909 CloseHandle(info.hThread);
910 CloseHandle(info.hProcess);
911
912 okChildInt("Arguments", "argcA", 5);
913 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
914 okChildString("Arguments", "argvA5", NULL);
915 okChildString("Arguments", "CommandLineA", buffer);
916 release_memory();
917 DeleteFileA(resfile);
918
919 memset(&startup, 0, sizeof(startup));
920 startup.cb = sizeof(startup);
921 startup.dwFlags = STARTF_USESHOWWINDOW;
922 startup.wShowWindow = SW_SHOWNORMAL;
923
924 /* from François */
925 get_file_name(resfile);
926 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
927 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
928 /* wait for child to terminate */
929 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
930 /* child process has changed result file, so let profile functions know about it */
931 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
932 CloseHandle(info.hThread);
933 CloseHandle(info.hProcess);
934
935 okChildInt("Arguments", "argcA", 7);
936 okChildString("Arguments", "argvA4", "a\"b\\");
937 okChildString("Arguments", "argvA5", "c\"");
938 okChildString("Arguments", "argvA6", "d");
939 okChildString("Arguments", "argvA7", NULL);
940 okChildString("Arguments", "CommandLineA", buffer);
941 release_memory();
942 DeleteFileA(resfile);
943
944 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
945 get_file_name(resfile);
946 /* Use exename to avoid buffer containing things like 'C:' */
947 sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
948 SetLastError(0xdeadbeef);
949 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
950 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
951 /* wait for child to terminate */
952 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
953 /* child process has changed result file, so let profile functions know about it */
954 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
955 CloseHandle(info.hThread);
956 CloseHandle(info.hProcess);
957 sprintf(buffer, "./%s", exename);
958 okChildString("Arguments", "argvA0", buffer);
959 release_memory();
960 DeleteFileA(resfile);
961
962 get_file_name(resfile);
963 /* Use exename to avoid buffer containing things like 'C:' */
964 sprintf(buffer, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
965 SetLastError(0xdeadbeef);
966 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
967 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
968 /* wait for child to terminate */
969 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
970 /* child process has changed result file, so let profile functions know about it */
971 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
972 CloseHandle(info.hThread);
973 CloseHandle(info.hProcess);
974 sprintf(buffer, ".\\%s", exename);
975 okChildString("Arguments", "argvA0", buffer);
976 release_memory();
977 DeleteFileA(resfile);
978
979 get_file_name(resfile);
980 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
981 assert ( lpFilePart != 0);
982 *(lpFilePart -1 ) = 0;
983 p = strrchr(fullpath, '\\');
984 /* Use exename to avoid buffer containing things like 'C:' */
985 if (p) sprintf(buffer, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p, exename, resfile);
986 else sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
987 SetLastError(0xdeadbeef);
988 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
989 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
990 /* wait for child to terminate */
991 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
992 /* child process has changed result file, so let profile functions know about it */
993 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
994 CloseHandle(info.hThread);
995 CloseHandle(info.hProcess);
996 if (p) sprintf(buffer, "..%s/%s", p, exename);
997 else sprintf(buffer, "./%s", exename);
998 okChildString("Arguments", "argvA0", buffer);
999 release_memory();
1000 DeleteFileA(resfile);
1001
1002 /* Using AppName */
1003 get_file_name(resfile);
1004 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
1005 assert ( lpFilePart != 0);
1006 *(lpFilePart -1 ) = 0;
1007 p = strrchr(fullpath, '\\');
1008 /* Use exename to avoid buffer containing things like 'C:' */
1009 if (p) sprintf(buffer, "..%s/%s", p, exename);
1010 else sprintf(buffer, "./%s", exename);
1011 sprintf(buffer2, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile);
1012 SetLastError(0xdeadbeef);
1013 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1014 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
1015 /* wait for child to terminate */
1016 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1017 /* child process has changed result file, so let profile functions know about it */
1018 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1019 CloseHandle(info.hThread);
1020 CloseHandle(info.hProcess);
1021 sprintf(buffer, "tests/process.c dump %s", resfile);
1022 okChildString("Arguments", "argvA0", "dummy");
1023 okChildString("Arguments", "CommandLineA", buffer2);
1024 okChildStringWA("Arguments", "CommandLineW", buffer2);
1025 release_memory();
1026 DeleteFileA(resfile);
1027
1028 if (0) /* Test crashes on NT-based Windows. */
1029 {
1030 /* Test NULL application name and command line parameters. */
1031 SetLastError(0xdeadbeef);
1032 ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1033 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1034 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1035 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1036 }
1037
1038 buffer[0] = '\0';
1039
1040 /* Test empty application name parameter. */
1041 SetLastError(0xdeadbeef);
1042 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1043 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1044 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1045 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1046 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1047 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1048
1049 buffer2[0] = '\0';
1050
1051 /* Test empty application name and command line parameters. */
1052 SetLastError(0xdeadbeef);
1053 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1054 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1055 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1056 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1057 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1058 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1059
1060 /* Test empty command line parameter. */
1061 SetLastError(0xdeadbeef);
1062 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1063 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1064 ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
1065 GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ ||
1066 GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ ||
1067 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */,
1068 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1069
1070 strcpy(buffer, "doesnotexist.exe");
1071 strcpy(buffer2, "does not exist.exe");
1072
1073 /* Test nonexistent application name. */
1074 SetLastError(0xdeadbeef);
1075 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1076 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1077 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1078
1079 SetLastError(0xdeadbeef);
1080 ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1081 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1082 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1083
1084 /* Test nonexistent command line parameter. */
1085 SetLastError(0xdeadbeef);
1086 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1087 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1088 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1089
1090 SetLastError(0xdeadbeef);
1091 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1092 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1093 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1094 }
1095
1096 static void test_Directory(void)
1097 {
1098 char buffer[MAX_PATH];
1099 PROCESS_INFORMATION info;
1100 STARTUPINFOA startup;
1101 char windir[MAX_PATH];
1102 static CHAR cmdline[] = "winver.exe";
1103
1104 memset(&startup, 0, sizeof(startup));
1105 startup.cb = sizeof(startup);
1106 startup.dwFlags = STARTF_USESHOWWINDOW;
1107 startup.wShowWindow = SW_SHOWNORMAL;
1108
1109 /* the basics */
1110 get_file_name(resfile);
1111 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1112 GetWindowsDirectoryA( windir, sizeof(windir) );
1113 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n");
1114 /* wait for child to terminate */
1115 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1116 /* child process has changed result file, so let profile functions know about it */
1117 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1118 CloseHandle(info.hThread);
1119 CloseHandle(info.hProcess);
1120
1121 okChildIString("Misc", "CurrDirA", windir);
1122 release_memory();
1123 DeleteFileA(resfile);
1124
1125 /* search PATH for the exe if directory is NULL */
1126 ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1127 ok(TerminateProcess(info.hProcess, 0), "Child process termination\n");
1128 CloseHandle(info.hThread);
1129 CloseHandle(info.hProcess);
1130
1131 /* if any directory is provided, don't search PATH, error on bad directory */
1132 SetLastError(0xdeadbeef);
1133 memset(&info, 0, sizeof(info));
1134 ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L,
1135 NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n");
1136 ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1137 ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n");
1138 }
1139
1140 static void test_Toolhelp(void)
1141 {
1142 char buffer[MAX_PATH];
1143 STARTUPINFOA startup;
1144 PROCESS_INFORMATION info;
1145 HANDLE process, thread, snapshot;
1146 PROCESSENTRY32 pe;
1147 THREADENTRY32 te;
1148 DWORD ret;
1149 int i;
1150
1151 memset(&startup, 0, sizeof(startup));
1152 startup.cb = sizeof(startup);
1153 startup.dwFlags = STARTF_USESHOWWINDOW;
1154 startup.wShowWindow = SW_SHOWNORMAL;
1155
1156 get_file_name(resfile);
1157 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1158 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1159 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1160 CloseHandle(info.hProcess);
1161 CloseHandle(info.hThread);
1162
1163 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1164 okChildInt("Toolhelp", "cntUsage", 0);
1165 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1166 okChildInt("Toolhelp", "th32ModuleID", 0);
1167 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1168 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1169 okChildInt("Toolhelp", "dwFlags", 0);
1170
1171 release_memory();
1172 DeleteFileA(resfile);
1173
1174 get_file_name(resfile);
1175 sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile);
1176 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1177 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1178
1179 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1180 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1181 CloseHandle(process);
1182
1183 CloseHandle(info.hProcess);
1184 CloseHandle(info.hThread);
1185
1186 for (i = 0; i < 20; i++)
1187 {
1188 SetLastError(0xdeadbeef);
1189 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1190 ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError());
1191 if (!process) break;
1192 CloseHandle(process);
1193 Sleep(100);
1194 }
1195 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1196 ok(i < 20 || broken(i == 20), "process object not released\n");
1197
1198 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1199 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1200 memset(&pe, 0, sizeof(pe));
1201 pe.dwSize = sizeof(pe);
1202 if (pProcess32First(snapshot, &pe))
1203 {
1204 while (pe.th32ParentProcessID != info.dwProcessId)
1205 if (!pProcess32Next(snapshot, &pe)) break;
1206 }
1207 CloseHandle(snapshot);
1208 ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n");
1209
1210 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID);
1211 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1212
1213 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1214 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1215 memset(&te, 0, sizeof(te));
1216 te.dwSize = sizeof(te);
1217 if (pThread32First(snapshot, &te))
1218 {
1219 while (te.th32OwnerProcessID != pe.th32ProcessID)
1220 if (!pThread32Next(snapshot, &te)) break;
1221 }
1222 CloseHandle(snapshot);
1223 ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1224
1225 thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID);
1226 ok(thread != NULL, "OpenThread failed %u\n", GetLastError());
1227 ret = ResumeThread(thread);
1228 ok(ret == 1, "expected 1, got %u\n", ret);
1229 CloseHandle(thread);
1230
1231 ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1232 CloseHandle(process);
1233
1234 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1235 okChildInt("Toolhelp", "cntUsage", 0);
1236 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1237 okChildInt("Toolhelp", "th32ModuleID", 0);
1238 okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1239 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1240 okChildInt("Toolhelp", "dwFlags", 0);
1241
1242 release_memory();
1243 DeleteFileA(resfile);
1244 }
1245
1246 static BOOL is_str_env_drive_dir(const char* str)
1247 {
1248 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1249 str[3] == '=' && str[4] == str[1];
1250 }
1251
1252 /* compared expected child's environment (in gesA) from actual
1253 * environment our child got
1254 */
1255 static void cmpEnvironment(const char* gesA)
1256 {
1257 int i, clen;
1258 const char* ptrA;
1259 char* res;
1260 char key[32];
1261 BOOL found;
1262
1263 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1264
1265 /* now look each parent env in child */
1266 if ((ptrA = gesA) != NULL)
1267 {
1268 while (*ptrA)
1269 {
1270 for (i = 0; i < clen; i++)
1271 {
1272 sprintf(key, "env%d", i);
1273 res = getChildString("EnvironmentA", key);
1274 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1275 break;
1276 }
1277 found = i < clen;
1278 ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1279
1280 ptrA += strlen(ptrA) + 1;
1281 release_memory();
1282 }
1283 }
1284 /* and each child env in parent */
1285 for (i = 0; i < clen; i++)
1286 {
1287 sprintf(key, "env%d", i);
1288 res = getChildString("EnvironmentA", key);
1289 if ((ptrA = gesA) != NULL)
1290 {
1291 while (*ptrA)
1292 {
1293 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1294 break;
1295 ptrA += strlen(ptrA) + 1;
1296 }
1297 if (!*ptrA) ptrA = NULL;
1298 }
1299
1300 if (!is_str_env_drive_dir(res))
1301 {
1302 found = ptrA != NULL;
1303 ok(found, "Child-env string %s isn't in parent process\n", res);
1304 }
1305 /* else => should also test we get the right per drive default directory here... */
1306 }
1307 }
1308
1309 static void test_Environment(void)
1310 {
1311 char buffer[MAX_PATH];
1312 PROCESS_INFORMATION info;
1313 STARTUPINFOA startup;
1314 char *child_env;
1315 int child_env_len;
1316 char *ptr;
1317 char *ptr2;
1318 char *env;
1319 int slen;
1320
1321 memset(&startup, 0, sizeof(startup));
1322 startup.cb = sizeof(startup);
1323 startup.dwFlags = STARTF_USESHOWWINDOW;
1324 startup.wShowWindow = SW_SHOWNORMAL;
1325
1326 /* the basics */
1327 get_file_name(resfile);
1328 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1329 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1330 /* wait for child to terminate */
1331 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1332 /* child process has changed result file, so let profile functions know about it */
1333 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1334
1335 env = GetEnvironmentStringsA();
1336 cmpEnvironment(env);
1337 release_memory();
1338 DeleteFileA(resfile);
1339
1340 memset(&startup, 0, sizeof(startup));
1341 startup.cb = sizeof(startup);
1342 startup.dwFlags = STARTF_USESHOWWINDOW;
1343 startup.wShowWindow = SW_SHOWNORMAL;
1344
1345 /* the basics */
1346 get_file_name(resfile);
1347 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1348
1349 child_env_len = 0;
1350 ptr = env;
1351 while(*ptr)
1352 {
1353 slen = strlen(ptr)+1;
1354 child_env_len += slen;
1355 ptr += slen;
1356 }
1357 /* Add space for additional environment variables */
1358 child_env_len += 256;
1359 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1360
1361 ptr = child_env;
1362 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1363 ptr += strlen(ptr) + 1;
1364 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1365 ptr += strlen(ptr) + 1;
1366 strcpy(ptr, "FOO=BAR");
1367 ptr += strlen(ptr) + 1;
1368 strcpy(ptr, "BAR=FOOBAR");
1369 ptr += strlen(ptr) + 1;
1370 /* copy all existing variables except:
1371 * - WINELOADER
1372 * - PATH (already set above)
1373 * - the directory definitions (=[A-Z]:=)
1374 */
1375 for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1376 {
1377 if (strncmp(ptr2, "PATH=", 5) != 0 &&
1378 strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1379 !is_str_env_drive_dir(ptr2))
1380 {
1381 strcpy(ptr, ptr2);
1382 ptr += strlen(ptr) + 1;
1383 }
1384 }
1385 *ptr = '\0';
1386 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1387 /* wait for child to terminate */
1388 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1389 /* child process has changed result file, so let profile functions know about it */
1390 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1391
1392 cmpEnvironment(child_env);
1393
1394 HeapFree(GetProcessHeap(), 0, child_env);
1395 FreeEnvironmentStringsA(env);
1396 release_memory();
1397 DeleteFileA(resfile);
1398 }
1399
1400 static void test_SuspendFlag(void)
1401 {
1402 char buffer[MAX_PATH];
1403 PROCESS_INFORMATION info;
1404 STARTUPINFOA startup, us;
1405 DWORD exit_status;
1406 char *result;
1407
1408 /* let's start simplistic */
1409 memset(&startup, 0, sizeof(startup));
1410 startup.cb = sizeof(startup);
1411 startup.dwFlags = STARTF_USESHOWWINDOW;
1412 startup.wShowWindow = SW_SHOWNORMAL;
1413
1414 get_file_name(resfile);
1415 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1416 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1417
1418 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1419 Sleep(1000);
1420 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1421 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1422
1423 /* wait for child to terminate */
1424 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1425 /* child process has changed result file, so let profile functions know about it */
1426 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1427
1428 GetStartupInfoA(&us);
1429
1430 okChildInt("StartupInfoA", "cb", startup.cb);
1431 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1432 result = getChildString( "StartupInfoA", "lpTitle" );
1433 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1434 "expected '%s' or null, got '%s'\n", selfname, result );
1435 okChildInt("StartupInfoA", "dwX", startup.dwX);
1436 okChildInt("StartupInfoA", "dwY", startup.dwY);
1437 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1438 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1439 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1440 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1441 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1442 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1443 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1444 release_memory();
1445 DeleteFileA(resfile);
1446 }
1447
1448 static void test_DebuggingFlag(void)
1449 {
1450 char buffer[MAX_PATH];
1451 void *processbase = NULL;
1452 PROCESS_INFORMATION info;
1453 STARTUPINFOA startup, us;
1454 DEBUG_EVENT de;
1455 unsigned dbg = 0;
1456 char *result;
1457
1458 /* let's start simplistic */
1459 memset(&startup, 0, sizeof(startup));
1460 startup.cb = sizeof(startup);
1461 startup.dwFlags = STARTF_USESHOWWINDOW;
1462 startup.wShowWindow = SW_SHOWNORMAL;
1463
1464 get_file_name(resfile);
1465 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1466 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1467
1468 /* get all startup events up to the entry point break exception */
1469 do
1470 {
1471 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1472 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1473 if (!dbg)
1474 {
1475 ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1476 "first event: %d\n", de.dwDebugEventCode);
1477 processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1478 }
1479 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1480 ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT ||
1481 de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1482 } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1483
1484 ok(dbg, "I have seen a debug event\n");
1485 /* wait for child to terminate */
1486 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1487 /* child process has changed result file, so let profile functions know about it */
1488 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1489
1490 GetStartupInfoA(&us);
1491
1492 okChildInt("StartupInfoA", "cb", startup.cb);
1493 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1494 result = getChildString( "StartupInfoA", "lpTitle" );
1495 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1496 "expected '%s' or null, got '%s'\n", selfname, result );
1497 okChildInt("StartupInfoA", "dwX", startup.dwX);
1498 okChildInt("StartupInfoA", "dwY", startup.dwY);
1499 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1500 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1501 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1502 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1503 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1504 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1505 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1506 release_memory();
1507 DeleteFileA(resfile);
1508 }
1509
1510 static BOOL is_console(HANDLE h)
1511 {
1512 return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1513 }
1514
1515 static void test_Console(void)
1516 {
1517 char buffer[MAX_PATH];
1518 PROCESS_INFORMATION info;
1519 STARTUPINFOA startup, us;
1520 SECURITY_ATTRIBUTES sa;
1521 CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC;
1522 DWORD modeIn, modeOut, modeInC, modeOutC;
1523 DWORD cpIn, cpOut, cpInC, cpOutC;
1524 DWORD w;
1525 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1526 const char* msg = "This is a std-handle inheritance test.";
1527 unsigned msg_len;
1528 BOOL run_tests = TRUE;
1529 char *result;
1530
1531 memset(&startup, 0, sizeof(startup));
1532 startup.cb = sizeof(startup);
1533 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1534 startup.wShowWindow = SW_SHOWNORMAL;
1535
1536 sa.nLength = sizeof(sa);
1537 sa.lpSecurityDescriptor = NULL;
1538 sa.bInheritHandle = TRUE;
1539
1540 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1541 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1542
1543 /* first, we need to be sure we're attached to a console */
1544 if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1545 {
1546 /* we're not attached to a console, let's do it */
1547 AllocConsole();
1548 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1549 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1550 }
1551 /* now verify everything's ok */
1552 ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1553 ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1554 startup.hStdError = startup.hStdOutput;
1555
1556 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1557 ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1558 ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1559 cpIn = GetConsoleCP();
1560 cpOut = GetConsoleOutputCP();
1561
1562 get_file_name(resfile);
1563 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile);
1564 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1565
1566 /* wait for child to terminate */
1567 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1568 /* child process has changed result file, so let profile functions know about it */
1569 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1570
1571 /* now get the modification the child has made, and resets parents expected values */
1572 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1573 ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1574 ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1575
1576 SetConsoleMode(startup.hStdInput, modeIn);
1577 SetConsoleMode(startup.hStdOutput, modeOut);
1578
1579 cpInC = GetConsoleCP();
1580 cpOutC = GetConsoleOutputCP();
1581
1582 /* Try to set invalid CP */
1583 SetLastError(0xdeadbeef);
1584 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1585 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1586 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1587 "GetLastError: expecting %u got %u\n",
1588 ERROR_INVALID_PARAMETER, GetLastError());
1589 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1590 run_tests = FALSE;
1591
1592
1593 SetLastError(0xdeadbeef);
1594 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1595 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1596 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1597 "GetLastError: expecting %u got %u\n",
1598 ERROR_INVALID_PARAMETER, GetLastError());
1599
1600 SetConsoleCP(cpIn);
1601 SetConsoleOutputCP(cpOut);
1602
1603 GetStartupInfoA(&us);
1604
1605 okChildInt("StartupInfoA", "cb", startup.cb);
1606 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1607 result = getChildString( "StartupInfoA", "lpTitle" );
1608 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1609 "expected '%s' or null, got '%s'\n", selfname, result );
1610 okChildInt("StartupInfoA", "dwX", startup.dwX);
1611 okChildInt("StartupInfoA", "dwY", startup.dwY);
1612 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1613 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1614 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1615 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1616 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1617 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1618 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1619
1620 /* check child correctly inherited the console */
1621 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1622 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1623 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1624 okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1625 okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1626 okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1627 okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1628 okChildInt("Console", "Attributes", sbi.wAttributes);
1629 okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1630 okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1631 okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1632 okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1633 okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1634 okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1635 okChildInt("Console", "InputCP", cpIn);
1636 okChildInt("Console", "OutputCP", cpOut);
1637 okChildInt("Console", "InputMode", modeIn);
1638 okChildInt("Console", "OutputMode", modeOut);
1639
1640 if (run_tests)
1641 {
1642 ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1643 ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1644 }
1645 else
1646 win_skip("Setting the codepage is not implemented\n");
1647
1648 ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1649 ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1650 trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1651 ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1652
1653 release_memory();
1654 DeleteFileA(resfile);
1655
1656 ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1657 ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(),
1658 &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1659 "Duplicating as inheritable child-output pipe\n");
1660 CloseHandle(hChildOut);
1661
1662 ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1663 ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(),
1664 &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1665 "Duplicating as inheritable child-input pipe\n");
1666 CloseHandle(hChildIn);
1667
1668 memset(&startup, 0, sizeof(startup));
1669 startup.cb = sizeof(startup);
1670 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1671 startup.wShowWindow = SW_SHOWNORMAL;
1672 startup.hStdInput = hChildInInh;
1673 startup.hStdOutput = hChildOutInh;
1674 startup.hStdError = hChildOutInh;
1675
1676 get_file_name(resfile);
1677 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile);
1678 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1679 ok(CloseHandle(hChildInInh), "Closing handle\n");
1680 ok(CloseHandle(hChildOutInh), "Closing handle\n");
1681
1682 msg_len = strlen(msg) + 1;
1683 ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1684 ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1685 memset(buffer, 0, sizeof(buffer));
1686 ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1687 ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1688
1689 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1690 ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1691
1692 /* wait for child to terminate */
1693 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1694 /* child process has changed result file, so let profile functions know about it */
1695 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1696
1697 okChildString("StdHandle", "msg", msg);
1698
1699 release_memory();
1700 DeleteFileA(resfile);
1701 }
1702
1703 static void test_ExitCode(void)
1704 {
1705 char buffer[MAX_PATH];
1706 PROCESS_INFORMATION info;
1707 STARTUPINFOA startup;
1708 DWORD code;
1709
1710 /* let's start simplistic */
1711 memset(&startup, 0, sizeof(startup));
1712 startup.cb = sizeof(startup);
1713 startup.dwFlags = STARTF_USESHOWWINDOW;
1714 startup.wShowWindow = SW_SHOWNORMAL;
1715
1716 get_file_name(resfile);
1717 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile);
1718 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1719
1720 /* wait for child to terminate */
1721 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1722 /* child process has changed result file, so let profile functions know about it */
1723 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1724
1725 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1726 okChildInt("ExitCode", "value", code);
1727
1728 release_memory();
1729 DeleteFileA(resfile);
1730 }
1731
1732 static void test_OpenProcess(void)
1733 {
1734 HANDLE hproc;
1735 void *addr1;
1736 MEMORY_BASIC_INFORMATION info;
1737 SIZE_T dummy, read_bytes;
1738 BOOL ret;
1739
1740 /* not exported in all windows versions */
1741 if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1742 win_skip("VirtualAllocEx not found\n");
1743 return;
1744 }
1745
1746 /* without PROCESS_VM_OPERATION */
1747 hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1748 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1749
1750 SetLastError(0xdeadbeef);
1751 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1752 ok(!addr1, "VirtualAllocEx should fail\n");
1753 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1754 { /* Win9x */
1755 CloseHandle(hproc);
1756 win_skip("VirtualAllocEx not implemented\n");
1757 return;
1758 }
1759 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1760
1761 read_bytes = 0xdeadbeef;
1762 SetLastError(0xdeadbeef);
1763 ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes);
1764 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1765 ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1766
1767 CloseHandle(hproc);
1768
1769 hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1770 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1771
1772 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1773 ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1774
1775 /* without PROCESS_QUERY_INFORMATION */
1776 SetLastError(0xdeadbeef);
1777 ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1778 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1779 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1780
1781 /* without PROCESS_VM_READ */
1782 read_bytes = 0xdeadbeef;
1783 SetLastError(0xdeadbeef);
1784 ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1785 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1786 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1787 ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1788
1789 CloseHandle(hproc);
1790
1791 hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1792
1793 memset(&info, 0xcc, sizeof(info));
1794 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1795 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1796
1797 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1798 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1799 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1800 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1801 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1802 /* NT reports Protect == 0 for a not committed memory block */
1803 ok(info.Protect == 0 /* NT */ ||
1804 info.Protect == PAGE_NOACCESS, /* Win9x */
1805 "%x != PAGE_NOACCESS\n", info.Protect);
1806 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1807
1808 SetLastError(0xdeadbeef);
1809 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1810 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1811 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1812
1813 CloseHandle(hproc);
1814
1815 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1816 if (hproc)
1817 {
1818 SetLastError(0xdeadbeef);
1819 memset(&info, 0xcc, sizeof(info));
1820 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1821 if (read_bytes) /* win8 */
1822 {
1823 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1824 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1825 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1826 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1827 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1828 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1829 ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
1830 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1831 }
1832 else /* before win8 */
1833 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1834
1835 SetLastError(0xdeadbeef);
1836 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1837 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1838 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1839
1840 CloseHandle(hproc);
1841 }
1842
1843 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1844 }
1845
1846 static void test_GetProcessVersion(void)
1847 {
1848 static char cmdline[] = "winver.exe";
1849 PROCESS_INFORMATION pi;
1850 STARTUPINFOA si;
1851 DWORD ret;
1852
1853 SetLastError(0xdeadbeef);
1854 ret = GetProcessVersion(0);
1855 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1856
1857 SetLastError(0xdeadbeef);
1858 ret = GetProcessVersion(GetCurrentProcessId());
1859 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1860
1861 memset(&si, 0, sizeof(si));
1862 si.cb = sizeof(si);
1863 si.dwFlags = STARTF_USESHOWWINDOW;
1864 si.wShowWindow = SW_HIDE;
1865 SetLastError(0xdeadbeef);
1866 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1867 ok(ret, "CreateProcess error %u\n", GetLastError());
1868
1869 SetLastError(0xdeadbeef);
1870 ret = GetProcessVersion(pi.dwProcessId);
1871 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1872
1873 SetLastError(0xdeadbeef);
1874 ret = TerminateProcess(pi.hProcess, 0);
1875 ok(ret, "TerminateProcess error %u\n", GetLastError());
1876
1877 CloseHandle(pi.hProcess);
1878 CloseHandle(pi.hThread);
1879 }
1880
1881 static void test_GetProcessImageFileNameA(void)
1882 {
1883 DWORD rc;
1884 CHAR process[MAX_PATH];
1885 static const char harddisk[] = "\\Device\\HarddiskVolume";
1886
1887 if (!pK32GetProcessImageFileNameA)
1888 {
1889 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1890 return;
1891 }
1892
1893 /* callers must guess the buffer size */
1894 SetLastError(0xdeadbeef);
1895 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1896 ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1897 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError());
1898
1899 *process = '\0';
1900 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1901 expect_eq_d(rc, lstrlenA(process));
1902 if (strncmp(process, harddisk, lstrlenA(harddisk)))
1903 {
1904 todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1905 return;
1906 }
1907
1908 if (!pQueryFullProcessImageNameA)
1909 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1910 else
1911 {
1912 CHAR image[MAX_PATH];
1913 DWORD length;
1914
1915 length = sizeof(image);
1916 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1917 expect_eq_d(length, lstrlenA(image));
1918 ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1919 }
1920 }
1921
1922 static void test_QueryFullProcessImageNameA(void)
1923 {
1924 #define INIT_STR "Just some words"
1925 DWORD length, size;
1926 CHAR buf[MAX_PATH], module[MAX_PATH];
1927
1928 if (!pQueryFullProcessImageNameA)
1929 {
1930 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1931 return;
1932 }
1933
1934 *module = '\0';
1935 SetLastError(0); /* old Windows don't reset it on success */
1936 size = GetModuleFileNameA(NULL, module, sizeof(module));
1937 ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError());
1938
1939 /* get the buffer length without \0 terminator */
1940 length = sizeof(buf);
1941 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1942 expect_eq_d(length, lstrlenA(buf));
1943 ok((buf[0] == '\\' && buf[1] == '\\') ||
1944 lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1945
1946 /* when the buffer is too small
1947 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1948 * - the size variable is not modified
1949 * tested with the biggest too small size
1950 */
1951 size = length;
1952 sprintf(buf,INIT_STR);
1953 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1954 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1955 expect_eq_d(length, size);
1956 expect_eq_s(INIT_STR, buf);
1957
1958 /* retest with smaller buffer size
1959 */
1960 size = 4;
1961 sprintf(buf,INIT_STR);
1962 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1963 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1964 expect_eq_d(4, size);
1965 expect_eq_s(INIT_STR, buf);
1966
1967 /* this is a difference between the ascii and the unicode version
1968 * the unicode version crashes when the size is big enough to hold
1969 * the result while the ascii version throws an error
1970 */
1971 size = 1024;
1972 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1973 expect_eq_d(1024, size);
1974 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
1975 }
1976
1977 static void test_QueryFullProcessImageNameW(void)
1978 {
1979 HANDLE hSelf;
1980 WCHAR module_name[1024], device[1024];
1981 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
1982 WCHAR buf[1024];
1983 DWORD size, len;
1984
1985 if (!pQueryFullProcessImageNameW)
1986 {
1987 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1988 return;
1989 }
1990
1991 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1992
1993 /* GetCurrentProcess pseudo-handle */
1994 size = sizeof(buf) / sizeof(buf[0]);
1995 expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
1996 expect_eq_d(lstrlenW(buf), size);
1997 expect_eq_ws_i(buf, module_name);
1998
1999 hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
2000 /* Real handle */
2001 size = sizeof(buf) / sizeof(buf[0]);
2002 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2003 expect_eq_d(lstrlenW(buf), size);
2004 expect_eq_ws_i(buf, module_name);
2005
2006 /* Buffer too small */
2007 size = lstrlenW(module_name)/2;
2008 lstrcpyW(buf, deviceW);
2009 SetLastError(0xdeadbeef);
2010 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2011 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2012 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2013 expect_eq_ws_i(deviceW, buf); /* buffer not changed */
2014
2015 /* Too small - not space for NUL terminator */
2016 size = lstrlenW(module_name);
2017 SetLastError(0xdeadbeef);
2018 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2019 expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
2020 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2021
2022 /* NULL buffer */
2023 size = 0;
2024 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
2025 expect_eq_d(0, size);
2026 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2027
2028 /* Buffer too small */
2029 size = lstrlenW(module_name)/2;
2030 SetLastError(0xdeadbeef);
2031 lstrcpyW(buf, module_name);
2032 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2033 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2034 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2035 expect_eq_ws_i(module_name, buf); /* buffer not changed */
2036
2037
2038 /* native path */
2039 size = sizeof(buf) / sizeof(buf[0]);
2040 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2041 expect_eq_d(lstrlenW(buf), size);
2042 ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2043 ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2044
2045 module_name[2] = '\0';
2046 *device = '\0';
2047 size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0]));
2048 ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2049 len = lstrlenW(device);
2050 ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2051
2052 if (size >= lstrlenW(buf))
2053 {
2054 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2055 }
2056 else
2057 {
2058 ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2059 buf[len] = '\0';
2060 ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2061 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));
2062 }
2063
2064 CloseHandle(hSelf);
2065 }
2066
2067 static void test_Handles(void)
2068 {
2069 HANDLE handle = GetCurrentProcess();
2070 HANDLE h2, h3;
2071 BOOL ret;
2072 DWORD code;
2073
2074 ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2075 handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2076 "invalid current process handle %p\n", handle );
2077 ret = GetExitCodeProcess( handle, &code );
2078 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2079 #ifdef _WIN64
2080 /* truncated handle */
2081 SetLastError( 0xdeadbeef );
2082 handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2083 ret = GetExitCodeProcess( handle, &code );
2084 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2085 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2086 /* sign-extended handle */
2087 SetLastError( 0xdeadbeef );
2088 handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle);
2089 ret = GetExitCodeProcess( handle, &code );
2090 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2091 /* invalid high-word */
2092 SetLastError( 0xdeadbeef );
2093 handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2094 ret = GetExitCodeProcess( handle, &code );
2095 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2096 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2097 #endif
2098
2099 handle = GetStdHandle( STD_ERROR_HANDLE );
2100 ok( handle != 0, "handle %p\n", handle );
2101 DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &h3,
2102 0, TRUE, DUPLICATE_SAME_ACCESS );
2103 SetStdHandle( STD_ERROR_HANDLE, h3 );
2104 CloseHandle( (HANDLE)STD_ERROR_HANDLE );
2105 h2 = GetStdHandle( STD_ERROR_HANDLE );
2106 ok( h2 == 0 ||
2107 broken( h2 == h3) || /* nt4, w2k */
2108 broken( h2 == INVALID_HANDLE_VALUE), /* win9x */
2109 "wrong handle %p/%p\n", h2, h3 );
2110 SetStdHandle( STD_ERROR_HANDLE, handle );
2111 }
2112
2113 static void test_IsWow64Process(void)
2114 {
2115 PROCESS_INFORMATION pi;
2116 STARTUPINFOA si;
2117 DWORD ret;
2118 BOOL is_wow64;
2119 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2120 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2121
2122 if (!pIsWow64Process)
2123 {
2124 skip("IsWow64Process is not available\n");
2125 return;
2126 }
2127
2128 memset(&si, 0, sizeof(si));
2129 si.cb = sizeof(si);
2130 si.dwFlags = STARTF_USESHOWWINDOW;
2131 si.wShowWindow = SW_HIDE;
2132 ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2133 if (ret)
2134 {
2135 trace("Created process %s\n", cmdline_wow64);
2136 is_wow64 = FALSE;
2137 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2138 ok(ret, "IsWow64Process failed.\n");
2139 ok(is_wow64, "is_wow64 returned FALSE.\n");
2140
2141 ret = TerminateProcess(pi.hProcess, 0);
2142 ok(ret, "TerminateProcess error\n");
2143
2144 CloseHandle(pi.hProcess);
2145 CloseHandle(pi.hThread);
2146 }
2147
2148 memset(&si, 0, sizeof(si));
2149 si.cb = sizeof(si);
2150 si.dwFlags = STARTF_USESHOWWINDOW;
2151 si.wShowWindow = SW_HIDE;
2152 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2153 if (ret)
2154 {
2155 trace("Created process %s\n", cmdline);
2156 is_wow64 = TRUE;
2157 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2158 ok(ret, "IsWow64Process failed.\n");
2159 ok(!is_wow64, "is_wow64 returned TRUE.\n");
2160
2161 ret = TerminateProcess(pi.hProcess, 0);
2162 ok(ret, "TerminateProcess error\n");
2163
2164 CloseHandle(pi.hProcess);
2165 CloseHandle(pi.hThread);
2166 }
2167 }
2168
2169 static void test_SystemInfo(void)
2170 {
2171 SYSTEM_INFO si, nsi;
2172 BOOL is_wow64;
2173
2174 if (!pGetNativeSystemInfo)
2175 {
2176 win_skip("GetNativeSystemInfo is not available\n");
2177 return;
2178 }
2179
2180 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2181
2182 GetSystemInfo(&si);
2183 pGetNativeSystemInfo(&nsi);
2184 if (is_wow64)
2185 {
2186 if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2187 {
2188 ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2189 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2190 S(U(nsi)).wProcessorArchitecture);
2191 ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664,
2192 "Expected PROCESSOR_AMD_X8664, got %d\n",
2193 nsi.dwProcessorType);
2194 }
2195 }
2196 else
2197 {
2198 ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2199 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2200 S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2201 ok(si.dwProcessorType == nsi.dwProcessorType,
2202 "Expected no difference for dwProcessorType, got %d and %d\n",
2203 si.dwProcessorType, nsi.dwProcessorType);
2204 }
2205 }
2206
2207 static void test_RegistryQuota(void)
2208 {
2209 BOOL ret;
2210 DWORD max_quota, used_quota;
2211
2212 if (!pGetSystemRegistryQuota)
2213 {
2214 win_skip("GetSystemRegistryQuota is not available\n");
2215 return;
2216 }
2217
2218 ret = pGetSystemRegistryQuota(NULL, NULL);
2219 ok(ret == TRUE,
2220 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2221
2222 ret = pGetSystemRegistryQuota(&max_quota, NULL);
2223 ok(ret == TRUE,
2224 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2225
2226 ret = pGetSystemRegistryQuota(NULL, &used_quota);
2227 ok(ret == TRUE,
2228 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2229
2230 ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2231 ok(ret == TRUE,
2232 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2233 }
2234
2235 static void test_TerminateProcess(void)
2236 {
2237 static char cmdline[] = "winver.exe";
2238 PROCESS_INFORMATION pi;
2239 STARTUPINFOA si;
2240 DWORD ret;
2241 HANDLE dummy, thread;
2242
2243 memset(&si, 0, sizeof(si));
2244 si.cb = sizeof(si);
2245 SetLastError(0xdeadbeef);
2246 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2247 ok(ret, "CreateProcess error %u\n", GetLastError());
2248
2249 SetLastError(0xdeadbeef);
2250 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2251 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2252
2253 /* create a not closed thread handle duplicate in the target process */
2254 SetLastError(0xdeadbeef);
2255 ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy,
2256 0, FALSE, DUPLICATE_SAME_ACCESS);
2257 ok(ret, "DuplicateHandle error %u\n", GetLastError());
2258
2259 SetLastError(0xdeadbeef);
2260 ret = TerminateThread(thread, 0);
2261 ok(ret, "TerminateThread error %u\n", GetLastError());
2262 CloseHandle(thread);
2263
2264 SetLastError(0xdeadbeef);
2265 ret = TerminateProcess(pi.hProcess, 0);
2266 ok(ret, "TerminateProcess error %u\n", GetLastError());
2267
2268 CloseHandle(pi.hProcess);
2269 CloseHandle(pi.hThread);
2270 }
2271
2272 static void test_DuplicateHandle(void)
2273 {
2274 char path[MAX_PATH], file_name[MAX_PATH];
2275 HANDLE f, fmin, out;
2276 DWORD info;
2277 BOOL r;
2278
2279 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2280 GetCurrentProcess(), &out, 0, FALSE,
2281 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2282 ok(r, "DuplicateHandle error %u\n", GetLastError());
2283 r = GetHandleInformation(out, &info);
2284 ok(r, "GetHandleInformation error %u\n", GetLastError());
2285 ok(info == 0, "info = %x\n", info);
2286 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2287 CloseHandle(out);
2288
2289 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2290 GetCurrentProcess(), &out, 0, TRUE,
2291 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2292 ok(r, "DuplicateHandle error %u\n", GetLastError());
2293 r = GetHandleInformation(out, &info);
2294 ok(r, "GetHandleInformation error %u\n", GetLastError());
2295 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2296 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2297 CloseHandle(out);
2298
2299 GetTempPathA(MAX_PATH, path);
2300 GetTempFileNameA(path, "wt", 0, file_name);
2301 f = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2302 if (f == INVALID_HANDLE_VALUE)
2303 {
2304 ok(0, "could not create %s\n", file_name);
2305 return;
2306 }
2307
2308 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2309 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2310 ok(r, "DuplicateHandle error %u\n", GetLastError());
2311 ok(f == out, "f != out\n");
2312 r = GetHandleInformation(out, &info);
2313 ok(r, "GetHandleInformation error %u\n", GetLastError());
2314 ok(info == 0, "info = %x\n", info);
2315
2316 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2317 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2318 ok(r, "DuplicateHandle error %u\n", GetLastError());
2319 ok(f == out, "f != out\n");
2320 r = GetHandleInformation(out, &info);
2321 ok(r, "GetHandleInformation error %u\n", GetLastError());
2322 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2323
2324 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
2325 ok(r, "SetHandleInformation error %u\n", GetLastError());
2326 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2327 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2328 ok(r, "DuplicateHandle error %u\n", GetLastError());
2329 ok(f != out, "f == out\n");
2330 r = GetHandleInformation(out, &info);
2331 ok(r, "GetHandleInformation error %u\n", GetLastError());
2332 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2333 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2334 ok(r, "SetHandleInformation error %u\n", GetLastError());
2335
2336 /* Test if DuplicateHandle allocates first free handle */
2337 if (f > out)
2338 {
2339 fmin = out;
2340 }
2341 else
2342 {
2343 fmin = f;
2344 f = out;
2345 }
2346 CloseHandle(fmin);
2347 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2348 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2349 ok(r, "DuplicateHandle error %u\n", GetLastError());
2350 ok(f == out, "f != out\n");
2351 CloseHandle(out);
2352 DeleteFileA(file_name);
2353
2354 f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2355 if (!is_console(f))
2356 {
2357 skip("DuplicateHandle on console handle\n");
2358 CloseHandle(f);
2359 return;
2360 }
2361
2362 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2363 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2364 ok(r, "DuplicateHandle error %u\n", GetLastError());
2365 todo_wine ok(f != out, "f == out\n");
2366 CloseHandle(out);
2367 }
2368
2369 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2370 static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2371 {
2372 LPOVERLAPPED overlapped;
2373 ULONG_PTR value;
2374 DWORD key;
2375 BOOL ret;
2376
2377 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait);
2378
2379 ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
2380 if (ret)
2381 {
2382 ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key);
2383 ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2384 ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2385 }
2386 }
2387
2388 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2389 static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2390 {
2391 BOOL ret;
2392 char buffer[MAX_PATH];
2393 STARTUPINFOA si = {0};
2394
2395 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command);
2396
2397 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2398 ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError());
2399 }
2400
2401 #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
2402 static void _test_assigned_proc(int line, HANDLE job, int expected_count, ...)
2403 {
2404 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20];
2405 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2406 DWORD ret_len, pid;
2407 va_list valist;
2408 int n;
2409 BOOL ret;
2410
2411 memset(buf, 0, sizeof(buf));
2412 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2413 ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2414 if (ret)
2415 {
2416 todo_wine_if(expected_count)
2417 ok_(__FILE__, line)(expected_count == pid_list->NumberOfAssignedProcesses,
2418 "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n",
2419 expected_count, pid_list->NumberOfAssignedProcesses);
2420 todo_wine_if(expected_count)
2421 ok_(__FILE__, line)(expected_count == pid_list->NumberOfProcessIdsInList,
2422 "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n",
2423 expected_count, pid_list->NumberOfProcessIdsInList);
2424
2425 va_start(valist, expected_count);
2426 for (n = 0; n < min(expected_count, pid_list->NumberOfProcessIdsInList); ++n)
2427 {
2428 pid = va_arg(valist, DWORD);
2429 ok_(__FILE__, line)(pid == pid_list->ProcessIdList[n],
2430 "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n",
2431 n, pid, pid_list->ProcessIdList[n]);
2432 }
2433 va_end(valist);
2434 }
2435 }
2436
2437 #define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc)
2438 static void _test_accounting(int line, HANDLE job, int total_proc, int active_proc, int terminated_proc)
2439 {
2440 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting;
2441 DWORD ret_len;
2442 BOOL ret;
2443
2444 memset(&basic_accounting, 0, sizeof(basic_accounting));
2445 ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting, sizeof(basic_accounting), &ret_len);
2446 ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2447 if (ret)
2448 {
2449 /* Not going to check process times or page faults */
2450
2451 todo_wine_if(total_proc)
2452 ok_(__FILE__, line)(total_proc == basic_accounting.TotalProcesses,
2453 "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n",
2454 total_proc, basic_accounting.TotalProcesses);
2455 todo_wine_if(active_proc)
2456 ok_(__FILE__, line)(active_proc == basic_accounting.ActiveProcesses,
2457 "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n",
2458 active_proc, basic_accounting.ActiveProcesses);
2459 ok_(__FILE__, line)(terminated_proc == basic_accounting.TotalTerminatedProcesses,
2460 "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n",
2461 terminated_proc, basic_accounting.TotalTerminatedProcesses);
2462 }
2463 }
2464
2465 static void test_IsProcessInJob(void)
2466 {
2467 HANDLE job, job2;
2468 PROCESS_INFORMATION pi;
2469 BOOL ret, out;
2470 DWORD dwret;
2471
2472 if (!pIsProcessInJob)
2473 {
2474 win_skip("IsProcessInJob not available.\n");
2475 return;
2476 }
2477
2478 job = pCreateJobObjectW(NULL, NULL);
2479 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2480
2481 job2 = pCreateJobObjectW(NULL, NULL);
2482 ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError());
2483
2484 create_process("wait", &pi);
2485
2486 out = TRUE;
2487 ret = pIsProcessInJob(pi.hProcess, job, &out);
2488 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2489 ok(!out, "IsProcessInJob returned out=%u\n", out);
2490 test_assigned_proc(job, 0);
2491 test_accounting(job, 0, 0, 0);
2492
2493 out = TRUE;
2494 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2495 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2496 ok(!out, "IsProcessInJob returned out=%u\n", out);
2497 test_assigned_proc(job2, 0);
2498 test_accounting(job2, 0, 0, 0);
2499
2500 out = TRUE;
2501 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2502 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2503 ok(!out, "IsProcessInJob returned out=%u\n", out);
2504
2505 ret = pAssignProcessToJobObject(job, pi.hProcess);
2506 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2507
2508 out = FALSE;
2509 ret = pIsProcessInJob(pi.hProcess, job, &out);
2510 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2511 ok(out, "IsProcessInJob returned out=%u\n", out);
2512 test_assigned_proc(job, 1, pi.dwProcessId);
2513 test_accounting(job, 1, 1, 0);
2514
2515 out = TRUE;
2516 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2517 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2518 ok(!out, "IsProcessInJob returned out=%u\n", out);
2519 test_assigned_proc(job2, 0);
2520 test_accounting(job2, 0, 0, 0);
2521
2522 out = FALSE;
2523 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2524 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2525 ok(out, "IsProcessInJob returned out=%u\n", out);
2526
2527 TerminateProcess(pi.hProcess, 0);
2528
2529 dwret = WaitForSingleObject(pi.hProcess, 1000);
2530 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2531
2532 out = FALSE;
2533 ret = pIsProcessInJob(pi.hProcess, job, &out);
2534 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2535 ok(out, "IsProcessInJob returned out=%u\n", out);
2536 test_assigned_proc(job, 0);
2537 test_accounting(job, 1, 0, 0);
2538
2539 CloseHandle(pi.hProcess);
2540 CloseHandle(pi.hThread);
2541 CloseHandle(job);
2542 CloseHandle(job2);
2543 }
2544
2545 static void test_TerminateJobObject(void)
2546 {
2547 HANDLE job;
2548 PROCESS_INFORMATION pi;
2549 BOOL ret;
2550 DWORD dwret;
2551
2552 job = pCreateJobObjectW(NULL, NULL);
2553 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2554 test_assigned_proc(job, 0);
2555 test_accounting(job, 0, 0, 0);
2556
2557 create_process("wait", &pi);
2558
2559 ret = pAssignProcessToJobObject(job, pi.hProcess);
2560 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2561 test_assigned_proc(job, 1, pi.dwProcessId);
2562 test_accounting(job, 1, 1, 0);
2563
2564 ret = pTerminateJobObject(job, 123);
2565 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2566
2567 dwret = WaitForSingleObject(pi.hProcess, 1000);
2568 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2569 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2570 test_assigned_proc(job, 0);
2571 test_accounting(job, 1, 0, 0);
2572
2573 ret = GetExitCodeProcess(pi.hProcess, &dwret);
2574 ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
2575 ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
2576 "wrong exitcode %u\n", dwret);
2577
2578 CloseHandle(pi.hProcess);
2579 CloseHandle(pi.hThread);
2580
2581 /* Test adding an already terminated process to a job object */
2582 create_process("exit", &pi);
2583
2584 dwret = WaitForSingleObject(pi.hProcess, 1000);
2585 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2586
2587 SetLastError(0xdeadbeef);
2588 ret = pAssignProcessToJobObject(job, pi.hProcess);
2589 ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2590 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2591 test_assigned_proc(job, 0);
2592 test_accounting(job, 1, 0, 0);
2593
2594 CloseHandle(pi.hProcess);
2595 CloseHandle(pi.hThread);
2596
2597 CloseHandle(job);
2598 }
2599
2600 static void test_QueryInformationJobObject(void)
2601 {
2602 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2603 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2604 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2605 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2606 DWORD dwret, ret_len;
2607 PROCESS_INFORMATION pi[2];
2608 HANDLE job;
2609 BOOL ret;
2610
2611 job = pCreateJobObjectW(NULL, NULL);
2612 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2613
2614 /* Only active processes are returned */
2615 create_process("exit", &pi[0]);
2616 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2617 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2618 dwret = WaitForSingleObject(pi[0].hProcess, 1000);
2619 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2620
2621 CloseHandle(pi[0].hProcess);
2622 CloseHandle(pi[0].hThread);
2623
2624 create_process("wait", &pi[0]);
2625 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2626 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2627
2628 create_process("wait", &pi[1]);
2629 ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2630 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2631
2632 SetLastError(0xdeadbeef);
2633 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2634 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len);
2635 ok(!ret, "QueryInformationJobObject expected failure\n");
2636 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2637
2638 SetLastError(0xdeadbeef);
2639 memset(buf, 0, sizeof(buf));
2640 pid_list->NumberOfAssignedProcesses = 42;
2641 pid_list->NumberOfProcessIdsInList = 42;
2642 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2643 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len);
2644 todo_wine
2645 ok(!ret, "QueryInformationJobObject expected failure\n");
2646 todo_wine
2647 expect_eq_d(ERROR_MORE_DATA, GetLastError());
2648 if (ret)
2649 {
2650 todo_wine
2651 expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2652 todo_wine
2653 expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2654 }
2655
2656 memset(buf, 0, sizeof(buf));
2657 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2658 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2659 if(ret)
2660 {
2661 if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2662 win_skip("Number of assigned processes broken on Win 8\n");
2663 else
2664 {
2665 ULONG_PTR *list = pid_list->ProcessIdList;
2666
2667 todo_wine
2668 ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]),
2669 "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2670
2671 todo_wine
2672 expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2673 todo_wine
2674 expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2675 todo_wine
2676 expect_eq_d(pi[0].dwProcessId, list[0]);
2677 todo_wine
2678 expect_eq_d(pi[1].dwProcessId, list[1]);
2679 }
2680 }
2681
2682 /* test JobObjectBasicLimitInformation */
2683 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2684 sizeof(*basic_limit_info) - 1, &ret_len);
2685 ok(!ret, "QueryInformationJobObject expected failure\n");
2686 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2687
2688 ret_len = 0xdeadbeef;
2689 memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2690 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2691 sizeof(*basic_limit_info), &ret_len);
2692 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2693 ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2694 expect_eq_d(0, basic_limit_info->LimitFlags);
2695
2696 /* test JobObjectExtendedLimitInformation */
2697 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2698 sizeof(ext_limit_info) - 1, &ret_len);
2699 ok(!ret, "QueryInformationJobObject expected failure\n");
2700 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2701
2702 ret_len = 0xdeadbeef;
2703 memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2704 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2705 sizeof(ext_limit_info), &ret_len);
2706 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2707 ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2708 expect_eq_d(0, basic_limit_info->LimitFlags);
2709
2710 TerminateProcess(pi[0].hProcess, 0);
2711 CloseHandle(pi[0].hProcess);
2712 CloseHandle(pi[0].hThread);
2713
2714 TerminateProcess(pi[1].hProcess, 0);
2715 CloseHandle(pi[1].hProcess);
2716 CloseHandle(pi[1].hThread);
2717
2718 CloseHandle(job);
2719 }
2720
2721 static void test_CompletionPort(void)
2722 {
2723 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
2724 PROCESS_INFORMATION pi;
2725 HANDLE job, port;
2726 DWORD dwret;
2727 BOOL ret;
2728
2729 job = pCreateJobObjectW(NULL, NULL);
2730 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2731
2732 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2733 ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
2734
2735 port_info.CompletionKey = job;
2736 port_info.CompletionPort = port;
2737 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2738 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2739
2740 create_process("wait", &pi);
2741
2742 ret = pAssignProcessToJobObject(job, pi.hProcess);
2743 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2744
2745 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2746
2747 TerminateProcess(pi.hProcess, 0);
2748 dwret = WaitForSingleObject(pi.hProcess, 1000);
2749 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2750
2751 test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2752 test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100);
2753
2754 CloseHandle(pi.hProcess);
2755 CloseHandle(pi.hThread);
2756 CloseHandle(job);
2757 CloseHandle(port);
2758 }
2759
2760 static void test_KillOnJobClose(void)
2761 {
2762 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2763 PROCESS_INFORMATION pi;
2764 DWORD dwret;
2765 HANDLE job;
2766 BOOL ret;
2767
2768 job = pCreateJobObjectW(NULL, NULL);
2769 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2770
2771 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
2772 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2773 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2774 {
2775 win_skip("Kill on job close limit not available\n");
2776 return;
2777 }
2778 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2779 test_assigned_proc(job, 0);
2780 test_accounting(job, 0, 0, 0);
2781
2782 create_process("wait", &pi);
2783
2784 ret = pAssignProcessToJobObject(job, pi.hProcess);
2785 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2786 test_assigned_proc(job, 1, pi.dwProcessId);
2787 test_accounting(job, 1, 1, 0);
2788
2789 CloseHandle(job);
2790
2791 dwret = WaitForSingleObject(pi.hProcess, 1000);
2792 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2793 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2794
2795 CloseHandle(pi.hProcess);
2796 CloseHandle(pi.hThread);
2797 }
2798
2799 static void test_WaitForJobObject(void)
2800 {
2801 HANDLE job;
2802 PROCESS_INFORMATION pi;
2803 BOOL ret;
2804 DWORD dwret;
2805
2806 /* test waiting for a job object when the process is killed */
2807 job = pCreateJobObjectW(NULL, NULL);
2808 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2809
2810 dwret = WaitForSingleObject(job, 100);
2811 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2812
2813 create_process("wait", &pi);
2814
2815 ret = pAssignProcessToJobObject(job, pi.hProcess);
2816 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2817
2818 dwret = WaitForSingleObject(job, 100);
2819 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2820
2821 ret = pTerminateJobObject(job, 123);
2822 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2823
2824 dwret = WaitForSingleObject(job, 500);
2825 ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2826 "WaitForSingleObject returned %u\n", dwret);
2827
2828 if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2829 {
2830 #ifdef __REACTOS__
2831 if (!ret)
2832 {
2833 ok(0, "HACK: Killing process to speed up the test\n");
2834 TerminateProcess(pi.hProcess, 0);
2835 }
2836 #endif
2837 CloseHandle(pi.hProcess);
2838 CloseHandle(pi.hThread);
2839 CloseHandle(job);
2840 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2841 return;
2842 }
2843
2844 /* the object is not reset immediately */
2845 dwret = WaitForSingleObject(job, 100);
2846 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2847
2848 CloseHandle(pi.hProcess);
2849 CloseHandle(pi.hThread);
2850
2851 /* creating a new process doesn't reset the signalled state */
2852 create_process("wait", &pi);
2853
2854 ret = pAssignProcessToJobObject(job, pi.hProcess);
2855 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2856
2857 dwret = WaitForSingleObject(job, 100);
2858 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2859
2860 ret = pTerminateJobObject(job, 123);
2861 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2862
2863 CloseHandle(pi.hProcess);
2864 CloseHandle(pi.hThread);
2865
2866 CloseHandle(job);
2867
2868 /* repeat the test, but this time the process terminates properly */
2869 job = pCreateJobObjectW(NULL, NULL);
2870 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2871
2872 dwret = WaitForSingleObject(job, 100);
2873 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2874
2875 create_process("exit", &pi);
2876
2877 ret = pAssignProcessToJobObject(job, pi.hProcess);
2878 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2879