ReactOS 0.4.16-dev-136-g52192f1
process.c
Go to the documentation of this file.
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
67static void (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO);
68static BOOL (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD);
69static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
70static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
71static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
72static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize);
73static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize);
74static DWORD (WINAPI *pK32GetProcessImageFileNameA)(HANDLE,LPSTR,DWORD);
75static HANDLE (WINAPI *pCreateJobObjectW)(LPSECURITY_ATTRIBUTES sa, LPCWSTR name);
76static BOOL (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process);
77static BOOL (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result);
78static BOOL (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code);
79static BOOL (WINAPI *pQueryInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len, LPDWORD ret_len);
80static BOOL (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len);
81static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads);
82static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR);
83static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
84static BOOL (WINAPI *pProcessIdToSessionId)(DWORD,DWORD*);
85static DWORD (WINAPI *pWTSGetActiveConsoleSessionId)(void);
86static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
87static BOOL (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*);
88static BOOL (WINAPI *pProcess32Next)(HANDLE, PROCESSENTRY32*);
89static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*);
90static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*);
92static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
93static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
94static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
95static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
96static DWORD (WINAPI *pGetActiveProcessorCount)(WORD);
97
98/* ############################### */
99static char base[MAX_PATH];
100static char selfname[MAX_PATH];
101static char* exename;
102static char resfile[MAX_PATH];
103
104static int myARGC;
105static 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
116static char memory[1024*256];
117static char* memory_index = memory;
118
119static 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
129static void release_memory(void)
130{
132}
133
134/* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
135
136static 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
150static 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
165static 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
173static 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 */
190static 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 */
217static BOOL init(void)
218{
219 char *p;
220
222 if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
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 */
275static 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 */
288static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...)
289{
291 char buffer[1024+4*MAX_LISTED_ENV_VAR];
292 DWORD w;
293
296 va_end(valist);
298}
299
300
301/******************************************************************
302 * doChild
303 *
304 * output most of the information in the child process
305 */
306static 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];
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,
334 siA.dwFlags, siA.wShowWindow,
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,
356 siW.dwFlags, siW.wShowWindow,
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 }
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",
386 pe.dwFlags, encodeA(pe.szExeFile));
387
388 /* output of environment (Ansi) */
389 ptrA_save = ptrA = GetEnvironmentStringsA();
390 if (ptrA)
391 {
393
394 childPrintf(hFile, "[EnvironmentA]\n");
395 i = 0;
396 while (*ptrA)
397 {
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 {
412
413 childPrintf(hFile, "[EnvironmentW]\n");
414 i = 0;
415 while (*ptrW)
416 {
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 {
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",
446 childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
448 childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n",
450 }
451 childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
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);
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;
478 ok( ret, "Setting cursor position (%d)\n", GetLastError());
479 }
480 if (option && strcmp(option, "stdhandle") == 0)
481 {
484
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);
500 ExitProcess(123);
501 }
502
504}
505
506static 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
518static 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 */
533static 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
549static 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
557static 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
565static 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
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
591static void ok_child_int( int line, const char *sect, const char *key, UINT expect )
592{
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
602static void test_Startup(void)
603{
604 char buffer[MAX_PATH];
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);
616 startup.wShowWindow = SW_SHOWNORMAL;
617
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 */
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);
642
643 /* not so simplistic now */
644 memset(&startup, 0, sizeof(startup));
645 startup.cb = sizeof(startup);
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
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 */
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);
682
683 /* not so simplistic now */
684 memset(&startup, 0, sizeof(startup));
685 startup.cb = sizeof(startup);
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
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 */
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);
722
723 /* not so simplistic now */
724 memset(&startup, 0, sizeof(startup));
725 startup.cb = sizeof(startup);
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
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 */
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);
762
763 /* not so simplistic now */
764 memset(&startup, 0, sizeof(startup));
765 startup.cb = sizeof(startup);
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
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 */
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);
804
805 /* not so simplistic now */
806 memset(&startup, 0, sizeof(startup));
807 startup.cb = sizeof(startup);
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
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 */
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);
844
845 /* not so simplistic now */
846 memset(&startup, 0, sizeof(startup));
847 startup.cb = sizeof(startup);
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
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 */
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);
884
885 /* TODO: test for A/W and W/A and W/W */
886}
887
888static void test_CommandLine(void)
889{
890 char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
891 char buffer2[MAX_PATH];
894 BOOL ret;
895
896 memset(&startup, 0, sizeof(startup));
897 startup.cb = sizeof(startup);
899 startup.wShowWindow = SW_SHOWNORMAL;
900
901 /* the basics */
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 */
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);
918
919 memset(&startup, 0, sizeof(startup));
920 startup.cb = sizeof(startup);
922 startup.wShowWindow = SW_SHOWNORMAL;
923
924 /* from François */
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 */
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);
943
944 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
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);
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 */
955 CloseHandle(info.hThread);
956 CloseHandle(info.hProcess);
957 sprintf(buffer, "./%s", exename);
958 okChildString("Arguments", "argvA0", buffer);
961
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);
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 */
972 CloseHandle(info.hThread);
973 CloseHandle(info.hProcess);
974 sprintf(buffer, ".\\%s", exename);
975 okChildString("Arguments", "argvA0", buffer);
978
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);
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 */
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);
1001
1002 /* Using AppName */
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 */
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);
1027
1028 if (0) /* Test crashes on NT-based Windows. */
1029 {
1030 /* Test NULL application name and command line parameters. */
1031 SetLastError(0xdeadbeef);
1033 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
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);
1043 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
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");
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");
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);
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);
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
1096static void test_Directory(void)
1097{
1098 char buffer[MAX_PATH];
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 */
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 */
1118 CloseHandle(info.hThread);
1119 CloseHandle(info.hProcess);
1120
1121 okChildIString("Misc", "CurrDirA", windir);
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));
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
1140static void test_Toolhelp(void)
1141{
1142 char buffer[MAX_PATH];
1146 PROCESSENTRY32 pe;
1147 THREADENTRY32 te;
1148 DWORD ret;
1149 int i;
1150
1151#if defined(__REACTOS__) && defined(_M_AMD64)
1153 {
1154 skip("ROSTESTS-372: Skipping test in kernel32_winetest:process test_Toolhelp because it leaves a process behind on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
1155 //return;
1156 }
1157#endif
1158
1159 memset(&startup, 0, sizeof(startup));
1160 startup.cb = sizeof(startup);
1161 startup.dwFlags = STARTF_USESHOWWINDOW;
1162 startup.wShowWindow = SW_SHOWNORMAL;
1163
1165 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1166 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1167 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1168 CloseHandle(info.hProcess);
1169 CloseHandle(info.hThread);
1170
1172 okChildInt("Toolhelp", "cntUsage", 0);
1173 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1174 okChildInt("Toolhelp", "th32ModuleID", 0);
1175 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1176 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1177 okChildInt("Toolhelp", "dwFlags", 0);
1178
1181
1182#if defined(__REACTOS__) && defined(_M_AMD64)
1184 {
1185 skip("ROSTESTS-371: Skipping kernel32_winetest:sync test_apc_deadlock because it fails on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
1186 }
1187 else
1188 {
1189#endif
1190
1192 sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile);
1193 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1194 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1195
1197 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1199
1200 CloseHandle(info.hProcess);
1201 CloseHandle(info.hThread);
1202#if defined(__REACTOS__) && defined(_M_AMD64)
1203 }
1204#endif
1205
1206 for (i = 0; i < 20; i++)
1207 {
1208 SetLastError(0xdeadbeef);
1210 ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError());
1211 if (!process) break;
1213 Sleep(100);
1214 }
1215 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1216 ok(i < 20 || broken(i == 20), "process object not released\n");
1217
1218 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1219 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1220 memset(&pe, 0, sizeof(pe));
1221 pe.dwSize = sizeof(pe);
1222 if (pProcess32First(snapshot, &pe))
1223 {
1224 while (pe.th32ParentProcessID != info.dwProcessId)
1225 if (!pProcess32Next(snapshot, &pe)) break;
1226 }
1228 ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n");
1229
1231 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1232
1233 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1234 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1235 memset(&te, 0, sizeof(te));
1236 te.dwSize = sizeof(te);
1237 if (pThread32First(snapshot, &te))
1238 {
1239 while (te.th32OwnerProcessID != pe.th32ProcessID)
1240 if (!pThread32Next(snapshot, &te)) break;
1241 }
1243 ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1244
1246 ok(thread != NULL, "OpenThread failed %u\n", GetLastError());
1248 ok(ret == 1, "expected 1, got %u\n", ret);
1250
1251 ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1253
1255 okChildInt("Toolhelp", "cntUsage", 0);
1256 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1257 okChildInt("Toolhelp", "th32ModuleID", 0);
1258 okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1259 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1260 okChildInt("Toolhelp", "dwFlags", 0);
1261
1264}
1265
1266static BOOL is_str_env_drive_dir(const char* str)
1267{
1268 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1269 str[3] == '=' && str[4] == str[1];
1270}
1271
1272/* compared expected child's environment (in gesA) from actual
1273 * environment our child got
1274 */
1275static void cmpEnvironment(const char* gesA)
1276{
1277 int i, clen;
1278 const char* ptrA;
1279 char* res;
1280 char key[32];
1281 BOOL found;
1282
1283 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1284
1285 /* now look each parent env in child */
1286 if ((ptrA = gesA) != NULL)
1287 {
1288 while (*ptrA)
1289 {
1290 for (i = 0; i < clen; i++)
1291 {
1292 sprintf(key, "env%d", i);
1293 res = getChildString("EnvironmentA", key);
1294 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1295 break;
1296 }
1297 found = i < clen;
1298 ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1299
1300 ptrA += strlen(ptrA) + 1;
1302 }
1303 }
1304 /* and each child env in parent */
1305 for (i = 0; i < clen; i++)
1306 {
1307 sprintf(key, "env%d", i);
1308 res = getChildString("EnvironmentA", key);
1309 if ((ptrA = gesA) != NULL)
1310 {
1311 while (*ptrA)
1312 {
1313 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1314 break;
1315 ptrA += strlen(ptrA) + 1;
1316 }
1317 if (!*ptrA) ptrA = NULL;
1318 }
1319
1321 {
1322 found = ptrA != NULL;
1323 ok(found, "Child-env string %s isn't in parent process\n", res);
1324 }
1325 /* else => should also test we get the right per drive default directory here... */
1326 }
1327}
1328
1329static void test_Environment(void)
1330{
1331 char buffer[MAX_PATH];
1334 char *child_env;
1335 int child_env_len;
1336 char *ptr;
1337 char *ptr2;
1338 char *env;
1339 int slen;
1340
1341 memset(&startup, 0, sizeof(startup));
1342 startup.cb = sizeof(startup);
1343 startup.dwFlags = STARTF_USESHOWWINDOW;
1344 startup.wShowWindow = SW_SHOWNORMAL;
1345
1346 /* the basics */
1348 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1349 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1350 /* wait for child to terminate */
1351 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1352 /* child process has changed result file, so let profile functions know about it */
1354
1359
1360 memset(&startup, 0, sizeof(startup));
1361 startup.cb = sizeof(startup);
1362 startup.dwFlags = STARTF_USESHOWWINDOW;
1363 startup.wShowWindow = SW_SHOWNORMAL;
1364
1365 /* the basics */
1367 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1368
1369 child_env_len = 0;
1370 ptr = env;
1371 while(*ptr)
1372 {
1373 slen = strlen(ptr)+1;
1374 child_env_len += slen;
1375 ptr += slen;
1376 }
1377 /* Add space for additional environment variables */
1378 child_env_len += 256;
1379 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1380
1381 ptr = child_env;
1382 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1383 ptr += strlen(ptr) + 1;
1384 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1385 ptr += strlen(ptr) + 1;
1386 strcpy(ptr, "FOO=BAR");
1387 ptr += strlen(ptr) + 1;
1388 strcpy(ptr, "BAR=FOOBAR");
1389 ptr += strlen(ptr) + 1;
1390 /* copy all existing variables except:
1391 * - WINELOADER
1392 * - PATH (already set above)
1393 * - the directory definitions (=[A-Z]:=)
1394 */
1395 for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1396 {
1397 if (strncmp(ptr2, "PATH=", 5) != 0 &&
1398 strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1399 !is_str_env_drive_dir(ptr2))
1400 {
1401 strcpy(ptr, ptr2);
1402 ptr += strlen(ptr) + 1;
1403 }
1404 }
1405 *ptr = '\0';
1406 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1407 /* wait for child to terminate */
1408 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1409 /* child process has changed result file, so let profile functions know about it */
1411
1412 cmpEnvironment(child_env);
1413
1414 HeapFree(GetProcessHeap(), 0, child_env);
1418}
1419
1420static void test_SuspendFlag(void)
1421{
1422 char buffer[MAX_PATH];
1425 DWORD exit_status;
1426 char *result;
1427
1428 /* let's start simplistic */
1429 memset(&startup, 0, sizeof(startup));
1430 startup.cb = sizeof(startup);
1431 startup.dwFlags = STARTF_USESHOWWINDOW;
1432 startup.wShowWindow = SW_SHOWNORMAL;
1433
1435 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1436 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1437
1438 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1439 Sleep(1000);
1440 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1441 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1442
1443 /* wait for child to terminate */
1444 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1445 /* child process has changed result file, so let profile functions know about it */
1447
1449
1450 okChildInt("StartupInfoA", "cb", startup.cb);
1451 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1452 result = getChildString( "StartupInfoA", "lpTitle" );
1453 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1454 "expected '%s' or null, got '%s'\n", selfname, result );
1455 okChildInt("StartupInfoA", "dwX", startup.dwX);
1456 okChildInt("StartupInfoA", "dwY", startup.dwY);
1457 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1458 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1459 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1460 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1461 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1462 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1463 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1466}
1467
1468static void test_DebuggingFlag(void)
1469{
1470 char buffer[MAX_PATH];
1471 void *processbase = NULL;
1474 DEBUG_EVENT de;
1475 unsigned dbg = 0;
1476 char *result;
1477
1478 /* let's start simplistic */
1479 memset(&startup, 0, sizeof(startup));
1480 startup.cb = sizeof(startup);
1481 startup.dwFlags = STARTF_USESHOWWINDOW;
1482 startup.wShowWindow = SW_SHOWNORMAL;
1483
1485 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1486 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1487
1488 /* get all startup events up to the entry point break exception */
1489 do
1490 {
1491 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1493 if (!dbg)
1494 {
1496 "first event: %d\n", de.dwDebugEventCode);
1497 processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1498 }
1499 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1501 de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1503
1504 ok(dbg, "I have seen a debug event\n");
1505 /* wait for child to terminate */
1506 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1507 /* child process has changed result file, so let profile functions know about it */
1509
1511
1512 okChildInt("StartupInfoA", "cb", startup.cb);
1513 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1514 result = getChildString( "StartupInfoA", "lpTitle" );
1515 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1516 "expected '%s' or null, got '%s'\n", selfname, result );
1517 okChildInt("StartupInfoA", "dwX", startup.dwX);
1518 okChildInt("StartupInfoA", "dwY", startup.dwY);
1519 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1520 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1521 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1522 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1523 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1524 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1525 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1528}
1529
1531{
1532 return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1533}
1534
1535static void test_Console(void)
1536{
1537 char buffer[MAX_PATH];
1542 DWORD modeIn, modeOut, modeInC, modeOutC;
1543 DWORD cpIn, cpOut, cpInC, cpOutC;
1544 DWORD w;
1545 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1546 const char* msg = "This is a std-handle inheritance test.";
1547 unsigned msg_len;
1549 char *result;
1550
1551 memset(&startup, 0, sizeof(startup));
1552 startup.cb = sizeof(startup);
1554 startup.wShowWindow = SW_SHOWNORMAL;
1555
1556 sa.nLength = sizeof(sa);
1557 sa.lpSecurityDescriptor = NULL;
1558 sa.bInheritHandle = TRUE;
1559
1560 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1561 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1562
1563 /* first, we need to be sure we're attached to a console */
1564 if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1565 {
1566 /* we're not attached to a console, let's do it */
1567 AllocConsole();
1568 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1569 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1570 }
1571 /* now verify everything's ok */
1572 ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1573 ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1574 startup.hStdError = startup.hStdOutput;
1575
1576 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1577 ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1578 ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1579 cpIn = GetConsoleCP();
1580 cpOut = GetConsoleOutputCP();
1581
1583 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile);
1584 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1585
1586 /* wait for child to terminate */
1587 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1588 /* child process has changed result file, so let profile functions know about it */
1590
1591 /* now get the modification the child has made, and resets parents expected values */
1592 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1593 ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1594 ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1595
1596 SetConsoleMode(startup.hStdInput, modeIn);
1597 SetConsoleMode(startup.hStdOutput, modeOut);
1598
1599 cpInC = GetConsoleCP();
1600 cpOutC = GetConsoleOutputCP();
1601
1602 /* Try to set invalid CP */
1603 SetLastError(0xdeadbeef);
1604 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1607 "GetLastError: expecting %u got %u\n",
1610 run_tests = FALSE;
1611
1612
1613 SetLastError(0xdeadbeef);
1614 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1617 "GetLastError: expecting %u got %u\n",
1619
1620 SetConsoleCP(cpIn);
1621 SetConsoleOutputCP(cpOut);
1622
1624
1625 okChildInt("StartupInfoA", "cb", startup.cb);
1626 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1627 result = getChildString( "StartupInfoA", "lpTitle" );
1628 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1629 "expected '%s' or null, got '%s'\n", selfname, result );
1630 okChildInt("StartupInfoA", "dwX", startup.dwX);
1631 okChildInt("StartupInfoA", "dwY", startup.dwY);
1632 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1633 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1634 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1635 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1636 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1637 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1638 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1639
1640 /* check child correctly inherited the console */
1641 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1642 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1643 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1644 okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1645 okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1646 okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1647 okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1648 okChildInt("Console", "Attributes", sbi.wAttributes);
1649 okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1650 okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1651 okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1652 okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1653 okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1654 okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1655 okChildInt("Console", "InputCP", cpIn);
1656 okChildInt("Console", "OutputCP", cpOut);
1657 okChildInt("Console", "InputMode", modeIn);
1658 okChildInt("Console", "OutputMode", modeOut);
1659
1660 if (run_tests)
1661 {
1662 ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1663 ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1664 }
1665 else
1666 win_skip("Setting the codepage is not implemented\n");
1667
1668 ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1669 ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1670 trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1671 ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1672
1675
1676 ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1678 &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1679 "Duplicating as inheritable child-output pipe\n");
1680 CloseHandle(hChildOut);
1681
1682 ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1684 &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1685 "Duplicating as inheritable child-input pipe\n");
1686 CloseHandle(hChildIn);
1687
1688 memset(&startup, 0, sizeof(startup));
1689 startup.cb = sizeof(startup);
1691 startup.wShowWindow = SW_SHOWNORMAL;
1692 startup.hStdInput = hChildInInh;
1693 startup.hStdOutput = hChildOutInh;
1694 startup.hStdError = hChildOutInh;
1695
1697 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile);
1698 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1699 ok(CloseHandle(hChildInInh), "Closing handle\n");
1700 ok(CloseHandle(hChildOutInh), "Closing handle\n");
1701
1702 msg_len = strlen(msg) + 1;
1703 ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1704 ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1705 memset(buffer, 0, sizeof(buffer));
1706 ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1707 ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1708
1709 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1710 ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1711
1712 /* wait for child to terminate */
1713 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1714 /* child process has changed result file, so let profile functions know about it */
1716
1717 okChildString("StdHandle", "msg", msg);
1718
1721}
1722
1723static void test_ExitCode(void)
1724{
1725 char buffer[MAX_PATH];
1728 DWORD code;
1729
1730 /* let's start simplistic */
1731 memset(&startup, 0, sizeof(startup));
1732 startup.cb = sizeof(startup);
1733 startup.dwFlags = STARTF_USESHOWWINDOW;
1734 startup.wShowWindow = SW_SHOWNORMAL;
1735
1737 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile);
1738 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1739
1740 /* wait for child to terminate */
1741 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1742 /* child process has changed result file, so let profile functions know about it */
1744
1745 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1746 okChildInt("ExitCode", "value", code);
1747
1750}
1751
1752static void test_OpenProcess(void)
1753{
1754 HANDLE hproc;
1755 void *addr1;
1758 BOOL ret;
1759
1760 /* not exported in all windows versions */
1761 if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1762 win_skip("VirtualAllocEx not found\n");
1763 return;
1764 }
1765
1766 /* without PROCESS_VM_OPERATION */
1768 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1769
1770 SetLastError(0xdeadbeef);
1771 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1772 ok(!addr1, "VirtualAllocEx should fail\n");
1774 { /* Win9x */
1775 CloseHandle(hproc);
1776 win_skip("VirtualAllocEx not implemented\n");
1777 return;
1778 }
1779 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1780
1781 read_bytes = 0xdeadbeef;
1782 SetLastError(0xdeadbeef);
1784 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1785 ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1786
1787 CloseHandle(hproc);
1788
1790 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1791
1792 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1793 ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1794
1795 /* without PROCESS_QUERY_INFORMATION */
1796 SetLastError(0xdeadbeef);
1797 ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1798 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1799 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1800
1801 /* without PROCESS_VM_READ */
1802 read_bytes = 0xdeadbeef;
1803 SetLastError(0xdeadbeef);
1804 ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1805 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1806 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1807 ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1808
1809 CloseHandle(hproc);
1810
1812
1813 memset(&info, 0xcc, sizeof(info));
1814 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1815 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1816
1817 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1818 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1819 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1820 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1821 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1822 /* NT reports Protect == 0 for a not committed memory block */
1823 ok(info.Protect == 0 /* NT */ ||
1824 info.Protect == PAGE_NOACCESS, /* Win9x */
1825 "%x != PAGE_NOACCESS\n", info.Protect);
1826 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1827
1828 SetLastError(0xdeadbeef);
1829 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1830 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1831 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1832
1833 CloseHandle(hproc);
1834
1836 if (hproc)
1837 {
1838 SetLastError(0xdeadbeef);
1839 memset(&info, 0xcc, sizeof(info));
1840 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1841 if (read_bytes) /* win8 */
1842 {
1843 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1844 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1845 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1846 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1847 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1848 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1849 ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
1850 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1851 }
1852 else /* before win8 */
1853 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1854
1855 SetLastError(0xdeadbeef);
1856 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1857 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1858 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1859
1860 CloseHandle(hproc);
1861 }
1862
1863 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1864}
1865
1866static void test_GetProcessVersion(void)
1867{
1868 static char cmdline[] = "winver.exe";
1870 STARTUPINFOA si;
1871 DWORD ret;
1872
1873 SetLastError(0xdeadbeef);
1875 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1876
1877 SetLastError(0xdeadbeef);
1879 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1880
1881 memset(&si, 0, sizeof(si));
1882 si.cb = sizeof(si);
1884 si.wShowWindow = SW_HIDE;
1885 SetLastError(0xdeadbeef);
1886 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1887 ok(ret, "CreateProcess error %u\n", GetLastError());
1888
1889 SetLastError(0xdeadbeef);
1890 ret = GetProcessVersion(pi.dwProcessId);
1891 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1892
1893 SetLastError(0xdeadbeef);
1894 ret = TerminateProcess(pi.hProcess, 0);
1895 ok(ret, "TerminateProcess error %u\n", GetLastError());
1896
1897 CloseHandle(pi.hProcess);
1898 CloseHandle(pi.hThread);
1899}
1900
1902{
1903 DWORD rc;
1905 static const char harddisk[] = "\\Device\\HarddiskVolume";
1906
1907 if (!pK32GetProcessImageFileNameA)
1908 {
1909 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1910 return;
1911 }
1912
1913 /* callers must guess the buffer size */
1914 SetLastError(0xdeadbeef);
1915 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1917 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError());
1918
1919 *process = '\0';
1920 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1922 if (strncmp(process, harddisk, lstrlenA(harddisk)))
1923 {
1924 todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1925 return;
1926 }
1927
1928 if (!pQueryFullProcessImageNameA)
1929 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1930 else
1931 {
1933 DWORD length;
1934
1935 length = sizeof(image);
1936 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1938 ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1939 }
1940}
1941
1943{
1944#define INIT_STR "Just some words"
1945 DWORD length, size;
1947
1948 if (!pQueryFullProcessImageNameA)
1949 {
1950 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1951 return;
1952 }
1953
1954 *module = '\0';
1955 SetLastError(0); /* old Windows don't reset it on success */
1957 ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError());
1958
1959 /* get the buffer length without \0 terminator */
1960 length = sizeof(buf);
1961 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1963 ok((buf[0] == '\\' && buf[1] == '\\') ||
1964 lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1965
1966 /* when the buffer is too small
1967 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1968 * - the size variable is not modified
1969 * tested with the biggest too small size
1970 */
1971 size = length;
1973 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1977
1978 /* retest with smaller buffer size
1979 */
1980 size = 4;
1982 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1984 expect_eq_d(4, size);
1986
1987 /* this is a difference between the ascii and the unicode version
1988 * the unicode version crashes when the size is big enough to hold
1989 * the result while the ascii version throws an error
1990 */
1991 size = 1024;
1992 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1993 expect_eq_d(1024, size);
1995}
1996
1998{
1999 HANDLE hSelf;
2000 WCHAR module_name[1024], device[1024];
2001 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
2002 WCHAR buf[1024];
2003 DWORD size, len;
2004
2005 if (!pQueryFullProcessImageNameW)
2006 {
2007 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
2008 return;
2009 }
2010
2011 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
2012
2013 /* GetCurrentProcess pseudo-handle */
2014 size = sizeof(buf) / sizeof(buf[0]);
2015 expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
2018
2020 /* Real handle */
2021 size = sizeof(buf) / sizeof(buf[0]);
2022 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2025
2026 /* Buffer too small */
2029 SetLastError(0xdeadbeef);
2030 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2031 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2033 expect_eq_ws_i(deviceW, buf); /* buffer not changed */
2034
2035 /* Too small - not space for NUL terminator */
2037 SetLastError(0xdeadbeef);
2038 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2039 expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
2041
2042 /* NULL buffer */
2043 size = 0;
2044 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
2045 expect_eq_d(0, size);
2047
2048 /* Buffer too small */
2050 SetLastError(0xdeadbeef);
2052 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2053 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2055 expect_eq_ws_i(module_name, buf); /* buffer not changed */
2056
2057
2058 /* native path */
2059 size = sizeof(buf) / sizeof(buf[0]);
2060 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2062 ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2063 ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2064
2065 module_name[2] = '\0';
2066 *device = '\0';
2067 size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0]));
2068 ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2069 len = lstrlenW(device);
2070 ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2071
2072 if (size >= lstrlenW(buf))
2073 {
2074 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2075 }
2076 else
2077 {
2078 ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2079 buf[len] = '\0';
2080 ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2081 ok(lstrcmpiW(module_name+3, buf+len+1) == 0, "expected '%s' to match '%s'\n", wine_dbgstr_w(module_name+3), wine_dbgstr_w(buf+len+1));
2082 }
2083
2084 CloseHandle(hSelf);
2085}
2086
2087static void test_Handles(void)
2088{
2090 HANDLE h2, h3;
2091 BOOL ret;
2092 DWORD code;
2093
2094 ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2095 handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2096 "invalid current process handle %p\n", handle );
2098 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2099#ifdef _WIN64
2100 /* truncated handle */
2101 SetLastError( 0xdeadbeef );
2102 handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2104 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2105 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2106 /* sign-extended handle */
2107 SetLastError( 0xdeadbeef );
2110 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2111 /* invalid high-word */
2112 SetLastError( 0xdeadbeef );
2113 handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2115 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2116 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2117#endif
2118
2120 ok( handle != 0, "handle %p\n", handle );
2126 ok( h2 == 0 ||
2127 broken( h2 == h3) || /* nt4, w2k */
2128 broken( h2 == INVALID_HANDLE_VALUE), /* win9x */
2129 "wrong handle %p/%p\n", h2, h3 );
2131}
2132
2133static void test_IsWow64Process(void)
2134{
2136 STARTUPINFOA si;
2137 DWORD ret;
2138 BOOL is_wow64;
2139 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2140 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2141
2142 if (!pIsWow64Process)
2143 {
2144 skip("IsWow64Process is not available\n");
2145 return;
2146 }
2147
2148 memset(&si, 0, sizeof(si));
2149 si.cb = sizeof(si);
2151 si.wShowWindow = SW_HIDE;
2152 ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2153 if (ret)
2154 {
2155 trace("Created process %s\n", cmdline_wow64);
2156 is_wow64 = FALSE;
2157 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2158 ok(ret, "IsWow64Process failed.\n");
2159 ok(is_wow64, "is_wow64 returned FALSE.\n");
2160
2161 ret = TerminateProcess(pi.hProcess, 0);
2162 ok(ret, "TerminateProcess error\n");
2163
2164 CloseHandle(pi.hProcess);
2165 CloseHandle(pi.hThread);
2166 }
2167
2168 memset(&si, 0, sizeof(si));
2169 si.cb = sizeof(si);
2171 si.wShowWindow = SW_HIDE;
2172 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2173 if (ret)
2174 {
2175 trace("Created process %s\n", cmdline);
2176 is_wow64 = TRUE;
2177 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2178 ok(ret, "IsWow64Process failed.\n");
2179 ok(!is_wow64, "is_wow64 returned TRUE.\n");
2180
2181 ret = TerminateProcess(pi.hProcess, 0);
2182 ok(ret, "TerminateProcess error\n");
2183
2184 CloseHandle(pi.hProcess);
2185 CloseHandle(pi.hThread);
2186 }
2187}
2188
2189static void test_SystemInfo(void)
2190{
2191 SYSTEM_INFO si, nsi;
2192 BOOL is_wow64;
2193
2194 if (!pGetNativeSystemInfo)
2195 {
2196 win_skip("GetNativeSystemInfo is not available\n");
2197 return;
2198 }
2199
2200 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2201
2202 GetSystemInfo(&si);
2203 pGetNativeSystemInfo(&nsi);
2204 if (is_wow64)
2205 {
2206 if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2207 {
2208 ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2209 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2210 S(U(nsi)).wProcessorArchitecture);
2212 "Expected PROCESSOR_AMD_X8664, got %d\n",
2213 nsi.dwProcessorType);
2214 }
2215 }
2216 else
2217 {
2218 ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2219 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2220 S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2222 "Expected no difference for dwProcessorType, got %d and %d\n",
2224 }
2225}
2226
2227static void test_RegistryQuota(void)
2228{
2229 BOOL ret;
2230 DWORD max_quota, used_quota;
2231
2232 if (!pGetSystemRegistryQuota)
2233 {
2234 win_skip("GetSystemRegistryQuota is not available\n");
2235 return;
2236 }
2237
2238 ret = pGetSystemRegistryQuota(NULL, NULL);
2239 ok(ret == TRUE,
2240 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2241
2242 ret = pGetSystemRegistryQuota(&max_quota, NULL);
2243 ok(ret == TRUE,
2244 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2245
2246 ret = pGetSystemRegistryQuota(NULL, &used_quota);
2247 ok(ret == TRUE,
2248 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2249
2250 ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2251 ok(ret == TRUE,
2252 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2253}
2254
2255static void test_TerminateProcess(void)
2256{
2257 static char cmdline[] = "winver.exe";
2259 STARTUPINFOA si;
2260 DWORD ret;
2262
2263 memset(&si, 0, sizeof(si));
2264 si.cb = sizeof(si);
2265 SetLastError(0xdeadbeef);
2267 ok(ret, "CreateProcess error %u\n", GetLastError());
2268
2269 SetLastError(0xdeadbeef);
2270 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2271 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2272
2273 /* create a not closed thread handle duplicate in the target process */
2274 SetLastError(0xdeadbeef);
2277 ok(ret, "DuplicateHandle error %u\n", GetLastError());
2278
2279 SetLastError(0xdeadbeef);
2281 ok(ret, "TerminateThread error %u\n", GetLastError());
2283
2284 SetLastError(0xdeadbeef);
2285 ret = TerminateProcess(pi.hProcess, 0);
2286 ok(ret, "TerminateProcess error %u\n", GetLastError());
2287
2288 CloseHandle(pi.hProcess);
2289 CloseHandle(pi.hThread);
2290}
2291
2292static void test_DuplicateHandle(void)
2293{
2295 HANDLE f, fmin, out;
2296 DWORD info;
2297 BOOL r;
2298
2300 GetCurrentProcess(), &out, 0, FALSE,
2302 ok(r, "DuplicateHandle error %u\n", GetLastError());
2304 ok(r, "GetHandleInformation error %u\n", GetLastError());
2305 ok(info == 0, "info = %x\n", info);
2306 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2308
2310 GetCurrentProcess(), &out, 0, TRUE,
2312 ok(r, "DuplicateHandle error %u\n", GetLastError());
2314 ok(r, "GetHandleInformation error %u\n", GetLastError());
2315 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2316 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2318
2320 GetTempFileNameA(path, "wt", 0, file_name);
2322 if (f == INVALID_HANDLE_VALUE)
2323 {
2324 ok(0, "could not create %s\n", file_name);
2325 return;
2326 }
2327
2330 ok(r, "DuplicateHandle error %u\n", GetLastError());
2331 ok(f == out, "f != out\n");
2333 ok(r, "GetHandleInformation error %u\n", GetLastError());
2334 ok(info == 0, "info = %x\n", info);
2335
2338 ok(r, "DuplicateHandle error %u\n", GetLastError());
2339 ok(f == out, "f != out\n");
2341 ok(r, "GetHandleInformation error %u\n", GetLastError());
2342 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2343
2345 ok(r, "SetHandleInformation error %u\n", GetLastError());
2348 ok(r, "DuplicateHandle error %u\n", GetLastError());
2349 ok(f != out, "f == out\n");
2351 ok(r, "GetHandleInformation error %u\n", GetLastError());
2352 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2354 ok(r, "SetHandleInformation error %u\n", GetLastError());
2355
2356 /* Test if DuplicateHandle allocates first free handle */
2357 if (f > out)
2358 {
2359 fmin = out;
2360 }
2361 else
2362 {
2363 fmin = f;
2364 f = out;
2365 }
2369 ok(r, "DuplicateHandle error %u\n", GetLastError());
2370 ok(f == out, "f != out\n");
2373
2374 f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2375 if (!is_console(f))
2376 {
2377 skip("DuplicateHandle on console handle\n");
2378 CloseHandle(f);
2379 return;
2380 }
2381
2384 ok(r, "DuplicateHandle error %u\n", GetLastError());
2385 todo_wine ok(f != out, "f == out\n");
2387}
2388
2389#define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2390static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2391{
2394 DWORD key;
2395 BOOL ret;
2396
2398
2399 ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
2400 if (ret)
2401 {
2402 ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key);
2403 ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2404 ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2405 }
2406}
2407
2408#define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2410{
2411 BOOL ret;
2412 char buffer[MAX_PATH];
2413 STARTUPINFOA si = {0};
2414
2415 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command);
2416
2417 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2418 ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError());
2419}
2420
2421#define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
2423{
2424 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20];
2426 DWORD ret_len, pid;
2428 int n;
2429 BOOL ret;
2430
2431 memset(buf, 0, sizeof(buf));
2432 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2433 ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2434 if (ret)
2435 {
2437 ok_(__FILE__, line)(expected_count == pid_list->NumberOfAssignedProcesses,
2438 "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n",
2441 ok_(__FILE__, line)(expected_count == pid_list->NumberOfProcessIdsInList,
2442 "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n",
2444
2446 for (n = 0; n < min(expected_count, pid_list->NumberOfProcessIdsInList); ++n)
2447 {
2448 pid = va_arg(valist, DWORD);
2449 ok_(__FILE__, line)(pid == pid_list->ProcessIdList[n],
2450 "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n",
2451 n, pid, pid_list->ProcessIdList[n]);
2452 }
2453 va_end(valist);
2454 }
2455}
2456
2457#define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc)
2458static void _test_accounting(int line, HANDLE job, int total_proc, int active_proc, int terminated_proc)
2459{
2461 DWORD ret_len;
2462 BOOL ret;
2463
2464 memset(&basic_accounting, 0, sizeof(basic_accounting));
2465 ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting, sizeof(basic_accounting), &ret_len);
2466 ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2467 if (ret)
2468 {
2469 /* Not going to check process times or page faults */
2470
2471 todo_wine_if(total_proc)
2472 ok_(__FILE__, line)(total_proc == basic_accounting.TotalProcesses,
2473 "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n",
2474 total_proc, basic_accounting.TotalProcesses);
2475 todo_wine_if(active_proc)
2476 ok_(__FILE__, line)(active_proc == basic_accounting.ActiveProcesses,
2477 "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n",
2478 active_proc, basic_accounting.ActiveProcesses);
2479 ok_(__FILE__, line)(terminated_proc == basic_accounting.TotalTerminatedProcesses,
2480 "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n",
2481 terminated_proc, basic_accounting.TotalTerminatedProcesses);
2482 }
2483}
2484
2485static void test_IsProcessInJob(void)
2486{
2487 HANDLE job, job2;
2489 BOOL ret, out;
2490 DWORD dwret;
2491
2492 if (!pIsProcessInJob)
2493 {
2494 win_skip("IsProcessInJob not available.\n");
2495 return;
2496 }
2497
2498 job = pCreateJobObjectW(NULL, NULL);
2499 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2500
2501 job2 = pCreateJobObjectW(NULL, NULL);
2502 ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError());
2503
2504 create_process("wait", &pi);
2505
2506 out = TRUE;
2507 ret = pIsProcessInJob(pi.hProcess, job, &out);
2508 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2509 ok(!out, "IsProcessInJob returned out=%u\n", out);
2511 test_accounting(job, 0, 0, 0);
2512
2513 out = TRUE;
2514 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2515 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2516 ok(!out, "IsProcessInJob returned out=%u\n", out);
2517 test_assigned_proc(job2, 0);
2518 test_accounting(job2, 0, 0, 0);
2519
2520 out = TRUE;
2521 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2522 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2523 ok(!out, "IsProcessInJob returned out=%u\n", out);
2524
2525 ret = pAssignProcessToJobObject(job, pi.hProcess);
2526 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2527
2528 out = FALSE;
2529 ret = pIsProcessInJob(pi.hProcess, job, &out);
2530 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2531 ok(out, "IsProcessInJob returned out=%u\n", out);
2532 test_assigned_proc(job, 1, pi.dwProcessId);
2533 test_accounting(job, 1, 1, 0);
2534
2535 out = TRUE;
2536 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2537 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2538 ok(!out, "IsProcessInJob returned out=%u\n", out);
2539 test_assigned_proc(job2, 0);
2540 test_accounting(job2, 0, 0, 0);
2541
2542 out = FALSE;
2543 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2544 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2545 ok(out, "IsProcessInJob returned out=%u\n", out);
2546
2547 TerminateProcess(pi.hProcess, 0);
2548
2549 dwret = WaitForSingleObject(pi.hProcess, 1000);
2550 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2551
2552 out = FALSE;
2553 ret = pIsProcessInJob(pi.hProcess, job, &out);
2554 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2555 ok(out, "IsProcessInJob returned out=%u\n", out);
2557 test_accounting(job, 1, 0, 0);
2558
2559 CloseHandle(pi.hProcess);
2560 CloseHandle(pi.hThread);
2562 CloseHandle(job2);
2563}
2564
2566{
2567 HANDLE job;
2569 BOOL ret;
2570 DWORD dwret;
2571
2572 job = pCreateJobObjectW(NULL, NULL);
2573 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2575 test_accounting(job, 0, 0, 0);
2576
2577 create_process("wait", &pi);
2578
2579 ret = pAssignProcessToJobObject(job, pi.hProcess);
2580 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2581 test_assigned_proc(job, 1, pi.dwProcessId);
2582 test_accounting(job, 1, 1, 0);
2583
2584 ret = pTerminateJobObject(job, 123);
2585 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2586
2587 dwret = WaitForSingleObject(pi.hProcess, 1000);
2588 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2589 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2591 test_accounting(job, 1, 0, 0);
2592
2593 ret = GetExitCodeProcess(pi.hProcess, &dwret);
2594 ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
2595 ok(dwret == 123 || broken(dwret == 0) || broken(dwret == 259) /* randomly fails on Win 2000 / XP */,
2596 "wrong exitcode %u\n", dwret);
2597
2598 CloseHandle(pi.hProcess);
2599 CloseHandle(pi.hThread);
2600
2601 /* Test adding an already terminated process to a job object */
2602 create_process("exit", &pi);
2603
2604 dwret = WaitForSingleObject(pi.hProcess, 1000);
2605 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2606
2607 SetLastError(0xdeadbeef);
2608 ret = pAssignProcessToJobObject(job, pi.hProcess);
2609 ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2612 test_accounting(job, 1, 0, 0);
2613
2614 CloseHandle(pi.hProcess);
2615 CloseHandle(pi.hThread);
2616
2618}
2619
2621{
2622 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2625 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2626 DWORD dwret, ret_len;
2628 HANDLE job;
2629 BOOL ret;
2630
2631 job = pCreateJobObjectW(NULL, NULL);
2632 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2633
2634 /* Only active processes are returned */
2635 create_process("exit", &pi[0]);
2636 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2637 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2638 dwret = WaitForSingleObject(pi[0].hProcess, 1000);
2639 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2640
2643
2644 create_process("wait", &pi[0]);
2645 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2646 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2647
2648 create_process("wait", &pi[1]);
2649 ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2650 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2651
2652 SetLastError(0xdeadbeef);
2655 ok(!ret, "QueryInformationJobObject expected failure\n");
2657
2658 SetLastError(0xdeadbeef);
2659 memset(buf, 0, sizeof(buf));
2660 pid_list->NumberOfAssignedProcesses = 42;
2661 pid_list->NumberOfProcessIdsInList = 42;
2664 todo_wine
2665 ok(!ret, "QueryInformationJobObject expected failure\n");
2666 todo_wine
2668 if (ret)
2669 {
2670 todo_wine
2672 todo_wine
2674 }
2675
2676 memset(buf, 0, sizeof(buf));
2677 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2678 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2679 if(ret)
2680 {
2681 if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2682 win_skip("Number of assigned processes broken on Win 8\n");
2683 else
2684 {
2685 ULONG_PTR *list = pid_list->ProcessIdList;
2686
2687 todo_wine
2689 "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2690
2691 todo_wine
2693 todo_wine
2695 todo_wine
2696 expect_eq_d(pi[0].dwProcessId, list[0]);
2697 todo_wine
2698 expect_eq_d(pi[1].dwProcessId, list[1]);
2699 }
2700 }
2701
2702 /* test JobObjectBasicLimitInformation */
2703 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2704 sizeof(*basic_limit_info) - 1, &ret_len);
2705 ok(!ret, "QueryInformationJobObject expected failure\n");
2707
2708 ret_len = 0xdeadbeef;
2709 memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2710 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2711 sizeof(*basic_limit_info), &ret_len);
2712 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2713 ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2714 expect_eq_d(0, basic_limit_info->LimitFlags);
2715
2716 /* test JobObjectExtendedLimitInformation */
2717 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2718 sizeof(ext_limit_info) - 1, &ret_len);
2719 ok(!ret, "QueryInformationJobObject expected failure\n");
2721
2722 ret_len = 0xdeadbeef;
2723 memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2724 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2725 sizeof(ext_limit_info), &ret_len);
2726 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2727 ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2728 expect_eq_d(0, basic_limit_info->LimitFlags);
2729
2733
2737
2739}
2740
2741static void test_CompletionPort(void)
2742{
2745 HANDLE job, port;
2746 DWORD dwret;
2747 BOOL ret;
2748
2749 job = pCreateJobObjectW(NULL, NULL);
2750 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2751
2752 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2753 ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
2754
2755 port_info.CompletionKey = job;
2756 port_info.CompletionPort = port;
2757 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2758 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2759
2760 create_process("wait", &pi);
2761
2762 ret = pAssignProcessToJobObject(job, pi.hProcess);
2763 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2764
2766
2767 TerminateProcess(pi.hProcess, 0);
2768 dwret = WaitForSingleObject(pi.hProcess, 1000);
2769 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2770
2773
2774 CloseHandle(pi.hProcess);
2775 CloseHandle(pi.hThread);
2778}
2779
2780static void test_KillOnJobClose(void)
2781{
2784 DWORD dwret;
2785 HANDLE job;
2786 BOOL ret;
2787
2788 job = pCreateJobObjectW(NULL, NULL);
2789 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2790
2792 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2794 {
2795 win_skip("Kill on job close limit not available\n");
2796 return;
2797 }
2798 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2800 test_accounting(job, 0, 0, 0);
2801
2802 create_process("wait", &pi);
2803
2804 ret = pAssignProcessToJobObject(job, pi.hProcess);
2805 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2806 test_assigned_proc(job, 1, pi.dwProcessId);
2807 test_accounting(job, 1, 1, 0);
2808
2810
2811 dwret = WaitForSingleObject(pi.hProcess, 1000);
2812 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2813 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2814
2815 CloseHandle(pi.hProcess);
2816 CloseHandle(pi.hThread);
2817}
2818
2819static void test_WaitForJobObject(void)
2820{
2821 HANDLE job;
2823 BOOL ret;
2824 DWORD dwret;
2825
2826 /* test waiting for a job object when the process is killed */
2827 job = pCreateJobObjectW(NULL, NULL);
2828 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2829
2830 dwret = WaitForSingleObject(job, 100);
2831 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2832
2833 create_process("wait", &pi);
2834
2835 ret = pAssignProcessToJobObject(job, pi.hProcess);
2836 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2837
2838 dwret = WaitForSingleObject(job, 100);
2839 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2840
2841 ret = pTerminateJobObject(job, 123);
2842 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2843
2844 dwret = WaitForSingleObject(job, 500);
2845 ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2846 "WaitForSingleObject returned %u\n", dwret);
2847
2848 if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2849 {
2850#ifdef __REACTOS__
2851 if (!ret)
2852 {
2853 ok(0, "HACK: Killing process to speed up the test\n");
2854 TerminateProcess(pi.hProcess, 0);
2855 }
2856#endif
2857 CloseHandle(pi.hProcess);
2858 CloseHandle(pi.hThread);
2860 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2861 return;
2862 }
2863
2864 /* the object is not reset immediately */
2865 dwret = WaitForSingleObject(job, 100);
2866 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2867
2868 CloseHandle(pi.hProcess);
2869 CloseHandle(pi.hThread);
2870
2871 /* creating a new process doesn't reset the signalled state */
2872 create_process("wait", &pi);
2873
2874 ret = pAssignProcessToJobObject(job, pi.hProcess);
2875 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2876
2877 dwret = WaitForSingleObject(job, 100);
2878 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2879
2880 ret = pTerminateJobObject(job, 123);
2881 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2882
2883 CloseHandle(pi.hProcess);
2884 CloseHandle(pi.hThread);
2885
2887
2888 /* repeat the test, but this time the process terminates properly */
2889 job = pCreateJobObjectW(NULL, NULL);
2890 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2891
2892 dwret = WaitForSingleObject(job, 100);
2893 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2894
2895 create_process("exit", &pi);
2896
2897 ret = pAssignProcessToJobObject(job, pi.hProcess);
2898 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2899
2900 dwret = WaitForSingleObject(job, 100);
2901 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2902
2903 CloseHandle(pi.hProcess);
2904 CloseHandle(pi.hThread);
2906}
2907
2909{
2910 HANDLE job;
2911 BOOL ret;
2912
2913 job = pCreateJobObjectW(NULL, NULL);
2914 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2915
2916 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2917 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2919 test_accounting(job, 1, 1, 0);
2920
2921 return job;
2922}
2923