Remove unnecessary executable bits
[reactos.git] / modules / rostests / winetests / kernel32 / process.c
1 /*
2 * Unit test suite for process functions
3 *
4 * Copyright 2002 Eric Pouech
5 * Copyright 2006 Dmitry Timoshkov
6 * Copyright 2014 Michael Müller
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "wincon.h"
34 #include "winnls.h"
35 #include "winternl.h"
36 #include "tlhelp32.h"
37
38 #include "wine/test.h"
39
40 #include "winnt.h"
41
42 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
43 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
44 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
45 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
46
47 #define expect_eq_d(expected, actual) \
48 do { \
49 int value = (actual); \
50 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
51 (expected), value); \
52 } while (0)
53 #define expect_eq_s(expected, actual) \
54 do { \
55 LPCSTR value = (actual); \
56 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
57 expected, value); \
58 } while (0)
59 #define expect_eq_ws_i(expected, actual) \
60 do { \
61 LPCWSTR value = (actual); \
62 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
63 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
64 } while (0)
65
66 static HINSTANCE hkernel32, hntdll;
67 static void (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO);
68 static BOOL (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD);
69 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
70 static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
71 static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
72 static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize);
73 static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize);
74 static DWORD (WINAPI *pK32GetProcessImageFileNameA)(HANDLE,LPSTR,DWORD);
75 static HANDLE (WINAPI *pCreateJobObjectW)(LPSECURITY_ATTRIBUTES sa, LPCWSTR name);
76 static BOOL (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process);
77 static BOOL (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result);
78 static BOOL (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code);
79 static BOOL (WINAPI *pQueryInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len, LPDWORD ret_len);
80 static BOOL (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len);
81 static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads);
82 static BOOL (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR);
83 static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
84 static BOOL (WINAPI *pProcessIdToSessionId)(DWORD,DWORD*);
85 static DWORD (WINAPI *pWTSGetActiveConsoleSessionId)(void);
86 static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
87 static BOOL (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*);
88 static BOOL (WINAPI *pProcess32Next)(HANDLE, PROCESSENTRY32*);
89 static BOOL (WINAPI *pThread32First)(HANDLE, THREADENTRY32*);
90 static BOOL (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*);
91 static BOOL (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
92 static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
93 static BOOL (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
94 static BOOL (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
95 static void (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
96 static DWORD (WINAPI *pGetActiveProcessorCount)(WORD);
97
98 /* ############################### */
99 static char base[MAX_PATH];
100 static char selfname[MAX_PATH];
101 static char* exename;
102 static char resfile[MAX_PATH];
103
104 static int myARGC;
105 static char** myARGV;
106
107 /* As some environment variables get very long on Unix, we only test for
108 * the first 127 bytes.
109 * Note that increasing this value past 256 may exceed the buffer size
110 * limitations of the *Profile functions (at least on Wine).
111 */
112 #define MAX_LISTED_ENV_VAR 128
113
114 /* ---------------- portable memory allocation thingie */
115
116 static char memory[1024*256];
117 static char* memory_index = memory;
118
119 static char* grab_memory(size_t len)
120 {
121 char* ret = memory_index;
122 /* align on dword */
123 len = (len + 3) & ~3;
124 memory_index += len;
125 assert(memory_index <= memory + sizeof(memory));
126 return ret;
127 }
128
129 static void release_memory(void)
130 {
131 memory_index = memory;
132 }
133
134 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
135
136 static const char* encodeA(const char* str)
137 {
138 char* ptr;
139 size_t len,i;
140
141 if (!str) return "";
142 len = strlen(str) + 1;
143 ptr = grab_memory(len * 2 + 1);
144 for (i = 0; i < len; i++)
145 sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
146 ptr[2 * len] = '\0';
147 return ptr;
148 }
149
150 static const char* encodeW(const WCHAR* str)
151 {
152 char* ptr;
153 size_t len,i;
154
155 if (!str) return "";
156 len = lstrlenW(str) + 1;
157 ptr = grab_memory(len * 4 + 1);
158 assert(ptr);
159 for (i = 0; i < len; i++)
160 sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
161 ptr[4 * len] = '\0';
162 return ptr;
163 }
164
165 static unsigned decode_char(char c)
166 {
167 if (c >= '0' && c <= '9') return c - '0';
168 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
169 assert(c >= 'A' && c <= 'F');
170 return c - 'A' + 10;
171 }
172
173 static char* decodeA(const char* str)
174 {
175 char* ptr;
176 size_t len,i;
177
178 len = strlen(str) / 2;
179 if (!len--) return NULL;
180 ptr = grab_memory(len + 1);
181 for (i = 0; i < len; i++)
182 ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
183 ptr[len] = '\0';
184 return ptr;
185 }
186
187 /* This will be needed to decode Unicode strings saved by the child process
188 * when we test Unicode functions.
189 */
190 static WCHAR* decodeW(const char* str)
191 {
192 size_t len;
193 WCHAR* ptr;
194 int i;
195
196 len = strlen(str) / 4;
197 if (!len--) return NULL;
198 ptr = (WCHAR*)grab_memory(len * 2 + 1);
199 for (i = 0; i < len; i++)
200 ptr[i] = (decode_char(str[4 * i]) << 12) |
201 (decode_char(str[4 * i + 1]) << 8) |
202 (decode_char(str[4 * i + 2]) << 4) |
203 (decode_char(str[4 * i + 3]) << 0);
204 ptr[len] = '\0';
205 return ptr;
206 }
207
208 /******************************************************************
209 * init
210 *
211 * generates basic information like:
212 * base: absolute path to curr dir
213 * selfname: the way to reinvoke ourselves
214 * exename: executable without the path
215 * function-pointers, which are not implemented in all windows versions
216 */
217 static BOOL init(void)
218 {
219 char *p;
220
221 myARGC = winetest_get_mainargs( &myARGV );
222 if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
223 strcpy(selfname, myARGV[0]);
224
225 /* Strip the path of selfname */
226 if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1;
227 else exename = selfname;
228
229 if ((p = strrchr(exename, '/')) != NULL) exename = p + 1;
230
231 hkernel32 = GetModuleHandleA("kernel32");
232 hntdll = GetModuleHandleA("ntdll.dll");
233
234 pNtQueryInformationProcess = (void *)GetProcAddress(hntdll, "NtQueryInformationProcess");
235
236 pGetNativeSystemInfo = (void *) GetProcAddress(hkernel32, "GetNativeSystemInfo");
237 pGetSystemRegistryQuota = (void *) GetProcAddress(hkernel32, "GetSystemRegistryQuota");
238 pIsWow64Process = (void *) GetProcAddress(hkernel32, "IsWow64Process");
239 pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
240 pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
241 pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA");
242 pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW");
243 pK32GetProcessImageFileNameA = (void *) GetProcAddress(hkernel32, "K32GetProcessImageFileNameA");
244 pCreateJobObjectW = (void *)GetProcAddress(hkernel32, "CreateJobObjectW");
245 pAssignProcessToJobObject = (void *)GetProcAddress(hkernel32, "AssignProcessToJobObject");
246 pIsProcessInJob = (void *)GetProcAddress(hkernel32, "IsProcessInJob");
247 pTerminateJobObject = (void *)GetProcAddress(hkernel32, "TerminateJobObject");
248 pQueryInformationJobObject = (void *)GetProcAddress(hkernel32, "QueryInformationJobObject");
249 pSetInformationJobObject = (void *)GetProcAddress(hkernel32, "SetInformationJobObject");
250 pCreateIoCompletionPort = (void *)GetProcAddress(hkernel32, "CreateIoCompletionPort");
251 pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode");
252 pProcessIdToSessionId = (void *)GetProcAddress(hkernel32, "ProcessIdToSessionId");
253 pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId");
254 pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
255 pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First");
256 pProcess32Next = (void *)GetProcAddress(hkernel32, "Process32Next");
257 pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First");
258 pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next");
259 pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
260 pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum");
261 pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
262 pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
263 pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
264 pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount");
265
266 return TRUE;
267 }
268
269 /******************************************************************
270 * get_file_name
271 *
272 * generates an absolute file_name for temporary file
273 *
274 */
275 static void get_file_name(char* buf)
276 {
277 char path[MAX_PATH];
278
279 buf[0] = '\0';
280 GetTempPathA(sizeof(path), path);
281 GetTempFileNameA(path, "wt", 0, buf);
282 }
283
284 /******************************************************************
285 * static void childPrintf
286 *
287 */
288 static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...)
289 {
290 va_list valist;
291 char buffer[1024+4*MAX_LISTED_ENV_VAR];
292 DWORD w;
293
294 va_start(valist, fmt);
295 vsprintf(buffer, fmt, valist);
296 va_end(valist);
297 WriteFile(h, buffer, strlen(buffer), &w, NULL);
298 }
299
300
301 /******************************************************************
302 * doChild
303 *
304 * output most of the information in the child process
305 */
306 static void doChild(const char* file, const char* option)
307 {
308 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
309 STARTUPINFOA siA;
310 STARTUPINFOW siW;
311 int i;
312 char *ptrA, *ptrA_save;
313 WCHAR *ptrW, *ptrW_save;
314 char bufA[MAX_PATH];
315 WCHAR bufW[MAX_PATH];
316 HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
317 HANDLE snapshot;
318 PROCESSENTRY32 pe;
319 BOOL ret;
320
321 if (hFile == INVALID_HANDLE_VALUE) return;
322
323 /* output of startup info (Ansi) */
324 GetStartupInfoA(&siA);
325 childPrintf(hFile,
326 "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
327 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
328 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
329 "dwFlags=%u\nwShowWindow=%u\n"
330 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
331 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
332 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize,
333 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute,
334 siA.dwFlags, siA.wShowWindow,
335 (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError);
336
337 /* check the console handles in the TEB */
338 childPrintf(hFile, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
339 (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput,
340 (DWORD_PTR)params->hStdError);
341
342 /* since GetStartupInfoW is only implemented in win2k,
343 * zero out before calling so we can notice the difference
344 */
345 memset(&siW, 0, sizeof(siW));
346 GetStartupInfoW(&siW);
347 childPrintf(hFile,
348 "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
349 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
350 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
351 "dwFlags=%u\nwShowWindow=%u\n"
352 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
353 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
354 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize,
355 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute,
356 siW.dwFlags, siW.wShowWindow,
357 (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError);
358
359 /* Arguments */
360 childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
361 for (i = 0; i < myARGC; i++)
362 {
363 childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
364 }
365 childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
366 childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
367
368 /* output toolhelp information */
369 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
370 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
371 memset(&pe, 0, sizeof(pe));
372 pe.dwSize = sizeof(pe);
373 if (pProcess32First(snapshot, &pe))
374 {
375 while (pe.th32ProcessID != GetCurrentProcessId())
376 if (!pProcess32Next(snapshot, &pe)) break;
377 }
378 CloseHandle(snapshot);
379 ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n");
380 childPrintf(hFile,
381 "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n"
382 "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n"
383 "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n",
384 pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID,
385 pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase,
386 pe.dwFlags, encodeA(pe.szExeFile));
387
388 /* output of environment (Ansi) */
389 ptrA_save = ptrA = GetEnvironmentStringsA();
390 if (ptrA)
391 {
392 char env_var[MAX_LISTED_ENV_VAR];
393
394 childPrintf(hFile, "[EnvironmentA]\n");
395 i = 0;
396 while (*ptrA)
397 {
398 lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR);
399 childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
400 i++;
401 ptrA += strlen(ptrA) + 1;
402 }
403 childPrintf(hFile, "len=%d\n\n", i);
404 FreeEnvironmentStringsA(ptrA_save);
405 }
406
407 /* output of environment (Unicode) */
408 ptrW_save = ptrW = GetEnvironmentStringsW();
409 if (ptrW)
410 {
411 WCHAR env_var[MAX_LISTED_ENV_VAR];
412
413 childPrintf(hFile, "[EnvironmentW]\n");
414 i = 0;
415 while (*ptrW)
416 {
417 lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1);
418 env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
419 childPrintf(hFile, "env%d=%s\n", i, encodeW(env_var));
420 i++;
421 ptrW += lstrlenW(ptrW) + 1;
422 }
423 childPrintf(hFile, "len=%d\n\n", i);
424 FreeEnvironmentStringsW(ptrW_save);
425 }
426
427 childPrintf(hFile, "[Misc]\n");
428 if (GetCurrentDirectoryA(sizeof(bufA), bufA))
429 childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
430 if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW))
431 childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
432 childPrintf(hFile, "\n");
433
434 if (option && strcmp(option, "console") == 0)
435 {
436 CONSOLE_SCREEN_BUFFER_INFO sbi;
437 HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE);
438 HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
439 DWORD modeIn, modeOut;
440
441 childPrintf(hFile, "[Console]\n");
442 if (GetConsoleScreenBufferInfo(hConOut, &sbi))
443 {
444 childPrintf(hFile, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
445 sbi.dwSize.X, sbi.dwSize.Y, sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y, sbi.wAttributes);
446 childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
447 sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom);
448 childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n",
449 sbi.dwMaximumWindowSize.X, sbi.dwMaximumWindowSize.Y);
450 }
451 childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
452 GetConsoleCP(), GetConsoleOutputCP());
453 if (GetConsoleMode(hConIn, &modeIn))
454 childPrintf(hFile, "InputMode=%u\n", modeIn);
455 if (GetConsoleMode(hConOut, &modeOut))
456 childPrintf(hFile, "OutputMode=%u\n", modeOut);
457
458 /* now that we have written all relevant information, let's change it */
459 SetLastError(0xdeadbeef);
460 ret = SetConsoleCP(1252);
461 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
462 {
463 win_skip("Setting the codepage is not implemented\n");
464 }
465 else
466 {
467 ok(ret, "Setting CP\n");
468 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
469 }
470
471 ret = SetConsoleMode(hConIn, modeIn ^ 1);
472 ok( ret, "Setting mode (%d)\n", GetLastError());
473 ret = SetConsoleMode(hConOut, modeOut ^ 1);
474 ok( ret, "Setting mode (%d)\n", GetLastError());
475 sbi.dwCursorPosition.X ^= 1;
476 sbi.dwCursorPosition.Y ^= 1;
477 ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition);
478 ok( ret, "Setting cursor position (%d)\n", GetLastError());
479 }
480 if (option && strcmp(option, "stdhandle") == 0)
481 {
482 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
483 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
484
485 if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE)
486 {
487 char buf[1024];
488 DWORD r, w;
489
490 ok(ReadFile(hStdIn, buf, sizeof(buf), &r, NULL) && r > 0, "Reading message from input pipe\n");
491 childPrintf(hFile, "[StdHandle]\nmsg=%s\n\n", encodeA(buf));
492 ok(WriteFile(hStdOut, buf, r, &w, NULL) && w == r, "Writing message to output pipe\n");
493 }
494 }
495
496 if (option && strcmp(option, "exit_code") == 0)
497 {
498 childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123);
499 CloseHandle(hFile);
500 ExitProcess(123);
501 }
502
503 CloseHandle(hFile);
504 }
505
506 static char* getChildString(const char* sect, const char* key)
507 {
508 char buf[1024+4*MAX_LISTED_ENV_VAR];
509 char* ret;
510
511 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
512 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
513 assert(!(strlen(buf) & 1));
514 ret = decodeA(buf);
515 return ret;
516 }
517
518 static WCHAR* getChildStringW(const char* sect, const char* key)
519 {
520 char buf[1024+4*MAX_LISTED_ENV_VAR];
521 WCHAR* ret;
522
523 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
524 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
525 assert(!(strlen(buf) & 1));
526 ret = decodeW(buf);
527 return ret;
528 }
529
530 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
531 * others... (windows uses stricmp while Un*x uses strcasecmp...)
532 */
533 static int wtstrcasecmp(const char* p1, const char* p2)
534 {
535 char c1, c2;
536
537 c1 = c2 = '@';
538 while (c1 == c2 && c1)
539 {
540 c1 = *p1++; c2 = *p2++;
541 if (c1 != c2)
542 {
543 c1 = toupper(c1); c2 = toupper(c2);
544 }
545 }
546 return c1 - c2;
547 }
548
549 static int strCmp(const char* s1, const char* s2, BOOL sensitive)
550 {
551 if (!s1 && !s2) return 0;
552 if (!s2) return -1;
553 if (!s1) return 1;
554 return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2);
555 }
556
557 static void ok_child_string( int line, const char *sect, const char *key,
558 const char *expect, int sensitive )
559 {
560 char* result = getChildString( sect, key );
561 ok_(__FILE__, line)( strCmp(result, expect, sensitive) == 0, "%s:%s expected '%s', got '%s'\n",
562 sect, key, expect ? expect : "(null)", result );
563 }
564
565 static void ok_child_stringWA( int line, const char *sect, const char *key,
566 const char *expect, int sensitive )
567 {
568 WCHAR* expectW;
569 CHAR* resultA;
570 DWORD len;
571 WCHAR* result = getChildStringW( sect, key );
572
573 len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0);
574 expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
575 MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len);
576
577 len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL);
578 resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR));
579 WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL);
580
581 if (sensitive)
582 ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
583 sect, key, expect ? expect : "(null)", resultA );
584 else
585 ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
586 sect, key, expect ? expect : "(null)", resultA );
587 HeapFree(GetProcessHeap(),0,expectW);
588 HeapFree(GetProcessHeap(),0,resultA);
589 }
590
591 static void ok_child_int( int line, const char *sect, const char *key, UINT expect )
592 {
593 UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile );
594 ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result );
595 }
596
597 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
598 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
599 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
600 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
601
602 static void test_Startup(void)
603 {
604 char buffer[MAX_PATH];
605 PROCESS_INFORMATION info;
606 STARTUPINFOA startup,si;
607 char *result;
608 static CHAR title[] = "I'm the title string",
609 desktop[] = "winsta0\\default",
610 empty[] = "";
611
612 /* let's start simplistic */
613 memset(&startup, 0, sizeof(startup));
614 startup.cb = sizeof(startup);
615 startup.dwFlags = STARTF_USESHOWWINDOW;
616 startup.wShowWindow = SW_SHOWNORMAL;
617
618 get_file_name(resfile);
619 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
620 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
621 /* wait for child to terminate */
622 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
623 /* child process has changed result file, so let profile functions know about it */
624 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
625 CloseHandle(info.hThread);
626 CloseHandle(info.hProcess);
627
628 GetStartupInfoA(&si);
629 okChildInt("StartupInfoA", "cb", startup.cb);
630 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
631 okChildInt("StartupInfoA", "dwX", startup.dwX);
632 okChildInt("StartupInfoA", "dwY", startup.dwY);
633 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
634 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
635 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
636 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
637 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
638 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
639 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
640 release_memory();
641 DeleteFileA(resfile);
642
643 /* not so simplistic now */
644 memset(&startup, 0, sizeof(startup));
645 startup.cb = sizeof(startup);
646 startup.dwFlags = STARTF_USESHOWWINDOW;
647 startup.wShowWindow = SW_SHOWNORMAL;
648 startup.lpTitle = title;
649 startup.lpDesktop = desktop;
650 startup.dwXCountChars = 0x12121212;
651 startup.dwYCountChars = 0x23232323;
652 startup.dwX = 0x34343434;
653 startup.dwY = 0x45454545;
654 startup.dwXSize = 0x56565656;
655 startup.dwYSize = 0x67676767;
656 startup.dwFillAttribute = 0xA55A;
657
658 get_file_name(resfile);
659 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
660 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
661 /* wait for child to terminate */
662 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
663 /* child process has changed result file, so let profile functions know about it */
664 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
665 CloseHandle(info.hThread);
666 CloseHandle(info.hProcess);
667
668 okChildInt("StartupInfoA", "cb", startup.cb);
669 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
670 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
671 okChildInt("StartupInfoA", "dwX", startup.dwX);
672 okChildInt("StartupInfoA", "dwY", startup.dwY);
673 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
674 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
675 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
676 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
677 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
678 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
679 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
680 release_memory();
681 DeleteFileA(resfile);
682
683 /* not so simplistic now */
684 memset(&startup, 0, sizeof(startup));
685 startup.cb = sizeof(startup);
686 startup.dwFlags = STARTF_USESHOWWINDOW;
687 startup.wShowWindow = SW_SHOWNORMAL;
688 startup.lpTitle = title;
689 startup.lpDesktop = NULL;
690 startup.dwXCountChars = 0x12121212;
691 startup.dwYCountChars = 0x23232323;
692 startup.dwX = 0x34343434;
693 startup.dwY = 0x45454545;
694 startup.dwXSize = 0x56565656;
695 startup.dwYSize = 0x67676767;
696 startup.dwFillAttribute = 0xA55A;
697
698 get_file_name(resfile);
699 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
700 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
701 /* wait for child to terminate */
702 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
703 /* child process has changed result file, so let profile functions know about it */
704 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
705 CloseHandle(info.hThread);
706 CloseHandle(info.hProcess);
707
708 okChildInt("StartupInfoA", "cb", startup.cb);
709 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
710 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
711 okChildInt("StartupInfoA", "dwX", startup.dwX);
712 okChildInt("StartupInfoA", "dwY", startup.dwY);
713 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
714 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
715 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
716 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
717 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
718 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
719 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
720 release_memory();
721 DeleteFileA(resfile);
722
723 /* not so simplistic now */
724 memset(&startup, 0, sizeof(startup));
725 startup.cb = sizeof(startup);
726 startup.dwFlags = STARTF_USESHOWWINDOW;
727 startup.wShowWindow = SW_SHOWNORMAL;
728 startup.lpTitle = title;
729 startup.lpDesktop = empty;
730 startup.dwXCountChars = 0x12121212;
731 startup.dwYCountChars = 0x23232323;
732 startup.dwX = 0x34343434;
733 startup.dwY = 0x45454545;
734 startup.dwXSize = 0x56565656;
735 startup.dwYSize = 0x67676767;
736 startup.dwFillAttribute = 0xA55A;
737
738 get_file_name(resfile);
739 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
740 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
741 /* wait for child to terminate */
742 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
743 /* child process has changed result file, so let profile functions know about it */
744 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
745 CloseHandle(info.hThread);
746 CloseHandle(info.hProcess);
747
748 okChildInt("StartupInfoA", "cb", startup.cb);
749 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
750 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
751 okChildInt("StartupInfoA", "dwX", startup.dwX);
752 okChildInt("StartupInfoA", "dwY", startup.dwY);
753 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
754 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
755 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
756 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
757 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
758 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
759 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
760 release_memory();
761 DeleteFileA(resfile);
762
763 /* not so simplistic now */
764 memset(&startup, 0, sizeof(startup));
765 startup.cb = sizeof(startup);
766 startup.dwFlags = STARTF_USESHOWWINDOW;
767 startup.wShowWindow = SW_SHOWNORMAL;
768 startup.lpTitle = NULL;
769 startup.lpDesktop = desktop;
770 startup.dwXCountChars = 0x12121212;
771 startup.dwYCountChars = 0x23232323;
772 startup.dwX = 0x34343434;
773 startup.dwY = 0x45454545;
774 startup.dwXSize = 0x56565656;
775 startup.dwYSize = 0x67676767;
776 startup.dwFillAttribute = 0xA55A;
777
778 get_file_name(resfile);
779 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
780 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
781 /* wait for child to terminate */
782 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
783 /* child process has changed result file, so let profile functions know about it */
784 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
785 CloseHandle(info.hThread);
786 CloseHandle(info.hProcess);
787
788 okChildInt("StartupInfoA", "cb", startup.cb);
789 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
790 result = getChildString( "StartupInfoA", "lpTitle" );
791 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
792 "expected '%s' or null, got '%s'\n", selfname, result );
793 okChildInt("StartupInfoA", "dwX", startup.dwX);
794 okChildInt("StartupInfoA", "dwY", startup.dwY);
795 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
796 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
797 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
798 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
799 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
800 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
801 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
802 release_memory();
803 DeleteFileA(resfile);
804
805 /* not so simplistic now */
806 memset(&startup, 0, sizeof(startup));
807 startup.cb = sizeof(startup);
808 startup.dwFlags = STARTF_USESHOWWINDOW;
809 startup.wShowWindow = SW_SHOWNORMAL;
810 startup.lpTitle = empty;
811 startup.lpDesktop = desktop;
812 startup.dwXCountChars = 0x12121212;
813 startup.dwYCountChars = 0x23232323;
814 startup.dwX = 0x34343434;
815 startup.dwY = 0x45454545;
816 startup.dwXSize = 0x56565656;
817 startup.dwYSize = 0x67676767;
818 startup.dwFillAttribute = 0xA55A;
819
820 get_file_name(resfile);
821 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
822 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
823 /* wait for child to terminate */
824 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
825 /* child process has changed result file, so let profile functions know about it */
826 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
827 CloseHandle(info.hThread);
828 CloseHandle(info.hProcess);
829
830 okChildInt("StartupInfoA", "cb", startup.cb);
831 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
832 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
833 okChildInt("StartupInfoA", "dwX", startup.dwX);
834 okChildInt("StartupInfoA", "dwY", startup.dwY);
835 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
836 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
837 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
838 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
839 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
840 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
841 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
842 release_memory();
843 DeleteFileA(resfile);
844
845 /* not so simplistic now */
846 memset(&startup, 0, sizeof(startup));
847 startup.cb = sizeof(startup);
848 startup.dwFlags = STARTF_USESHOWWINDOW;
849 startup.wShowWindow = SW_SHOWNORMAL;
850 startup.lpTitle = empty;
851 startup.lpDesktop = empty;
852 startup.dwXCountChars = 0x12121212;
853 startup.dwYCountChars = 0x23232323;
854 startup.dwX = 0x34343434;
855 startup.dwY = 0x45454545;
856 startup.dwXSize = 0x56565656;
857 startup.dwYSize = 0x67676767;
858 startup.dwFillAttribute = 0xA55A;
859
860 get_file_name(resfile);
861 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
862 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
863 /* wait for child to terminate */
864 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
865 /* child process has changed result file, so let profile functions know about it */
866 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
867 CloseHandle(info.hThread);
868 CloseHandle(info.hProcess);
869
870 okChildInt("StartupInfoA", "cb", startup.cb);
871 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
872 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
873 okChildInt("StartupInfoA", "dwX", startup.dwX);
874 okChildInt("StartupInfoA", "dwY", startup.dwY);
875 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
876 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
877 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
878 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
879 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
880 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
881 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
882 release_memory();
883 DeleteFileA(resfile);
884
885 /* TODO: test for A/W and W/A and W/W */
886 }
887
888 static void test_CommandLine(void)
889 {
890 char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
891 char buffer2[MAX_PATH];
892 PROCESS_INFORMATION info;
893 STARTUPINFOA startup;
894 BOOL ret;
895
896 memset(&startup, 0, sizeof(startup));
897 startup.cb = sizeof(startup);
898 startup.dwFlags = STARTF_USESHOWWINDOW;
899 startup.wShowWindow = SW_SHOWNORMAL;
900
901 /* the basics */
902 get_file_name(resfile);
903 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
904 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
905 /* wait for child to terminate */
906 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
907 /* child process has changed result file, so let profile functions know about it */
908 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
909 CloseHandle(info.hThread);
910 CloseHandle(info.hProcess);
911
912 okChildInt("Arguments", "argcA", 5);
913 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
914 okChildString("Arguments", "argvA5", NULL);
915 okChildString("Arguments", "CommandLineA", buffer);
916 release_memory();
917 DeleteFileA(resfile);
918
919 memset(&startup, 0, sizeof(startup));
920 startup.cb = sizeof(startup);
921 startup.dwFlags = STARTF_USESHOWWINDOW;
922 startup.wShowWindow = SW_SHOWNORMAL;
923
924 /* from François */
925 get_file_name(resfile);
926 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
927 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
928 /* wait for child to terminate */
929 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
930 /* child process has changed result file, so let profile functions know about it */
931 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
932 CloseHandle(info.hThread);
933 CloseHandle(info.hProcess);
934
935 okChildInt("Arguments", "argcA", 7);
936 okChildString("Arguments", "argvA4", "a\"b\\");
937 okChildString("Arguments", "argvA5", "c\"");
938 okChildString("Arguments", "argvA6", "d");
939 okChildString("Arguments", "argvA7", NULL);
940 okChildString("Arguments", "CommandLineA", buffer);
941 release_memory();
942 DeleteFileA(resfile);
943
944 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
945 get_file_name(resfile);
946 /* Use exename to avoid buffer containing things like 'C:' */
947 sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
948 SetLastError(0xdeadbeef);
949 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
950 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
951 /* wait for child to terminate */
952 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
953 /* child process has changed result file, so let profile functions know about it */
954 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
955 CloseHandle(info.hThread);
956 CloseHandle(info.hProcess);
957 sprintf(buffer, "./%s", exename);
958 okChildString("Arguments", "argvA0", buffer);
959 release_memory();
960 DeleteFileA(resfile);
961
962 get_file_name(resfile);
963 /* Use exename to avoid buffer containing things like 'C:' */
964 sprintf(buffer, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
965 SetLastError(0xdeadbeef);
966 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
967 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
968 /* wait for child to terminate */
969 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
970 /* child process has changed result file, so let profile functions know about it */
971 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
972 CloseHandle(info.hThread);
973 CloseHandle(info.hProcess);
974 sprintf(buffer, ".\\%s", exename);
975 okChildString("Arguments", "argvA0", buffer);
976 release_memory();
977 DeleteFileA(resfile);
978
979 get_file_name(resfile);
980 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
981 assert ( lpFilePart != 0);
982 *(lpFilePart -1 ) = 0;
983 p = strrchr(fullpath, '\\');
984 /* Use exename to avoid buffer containing things like 'C:' */
985 if (p) sprintf(buffer, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p, exename, resfile);
986 else sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
987 SetLastError(0xdeadbeef);
988 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
989 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
990 /* wait for child to terminate */
991 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
992 /* child process has changed result file, so let profile functions know about it */
993 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
994 CloseHandle(info.hThread);
995 CloseHandle(info.hProcess);
996 if (p) sprintf(buffer, "..%s/%s", p, exename);
997 else sprintf(buffer, "./%s", exename);
998 okChildString("Arguments", "argvA0", buffer);
999 release_memory();
1000 DeleteFileA(resfile);
1001
1002 /* Using AppName */
1003 get_file_name(resfile);
1004 GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
1005 assert ( lpFilePart != 0);
1006 *(lpFilePart -1 ) = 0;
1007 p = strrchr(fullpath, '\\');
1008 /* Use exename to avoid buffer containing things like 'C:' */
1009 if (p) sprintf(buffer, "..%s/%s", p, exename);
1010 else sprintf(buffer, "./%s", exename);
1011 sprintf(buffer2, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile);
1012 SetLastError(0xdeadbeef);
1013 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1014 ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
1015 /* wait for child to terminate */
1016 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1017 /* child process has changed result file, so let profile functions know about it */
1018 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1019 CloseHandle(info.hThread);
1020 CloseHandle(info.hProcess);
1021 sprintf(buffer, "tests/process.c dump %s", resfile);
1022 okChildString("Arguments", "argvA0", "dummy");
1023 okChildString("Arguments", "CommandLineA", buffer2);
1024 okChildStringWA("Arguments", "CommandLineW", buffer2);
1025 release_memory();
1026 DeleteFileA(resfile);
1027
1028 if (0) /* Test crashes on NT-based Windows. */
1029 {
1030 /* Test NULL application name and command line parameters. */
1031 SetLastError(0xdeadbeef);
1032 ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1033 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1034 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1035 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1036 }
1037
1038 buffer[0] = '\0';
1039
1040 /* Test empty application name parameter. */
1041 SetLastError(0xdeadbeef);
1042 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1043 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1044 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1045 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1046 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1047 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1048
1049 buffer2[0] = '\0';
1050
1051 /* Test empty application name and command line parameters. */
1052 SetLastError(0xdeadbeef);
1053 ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1054 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1055 ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1056 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1057 broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1058 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1059
1060 /* Test empty command line parameter. */
1061 SetLastError(0xdeadbeef);
1062 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1063 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1064 ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
1065 GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ ||
1066 GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ ||
1067 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */,
1068 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1069
1070 strcpy(buffer, "doesnotexist.exe");
1071 strcpy(buffer2, "does not exist.exe");
1072
1073 /* Test nonexistent application name. */
1074 SetLastError(0xdeadbeef);
1075 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1076 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1077 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1078
1079 SetLastError(0xdeadbeef);
1080 ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1081 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1082 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1083
1084 /* Test nonexistent command line parameter. */
1085 SetLastError(0xdeadbeef);
1086 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1087 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1088 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1089
1090 SetLastError(0xdeadbeef);
1091 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1092 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1093 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1094 }
1095
1096 static void test_Directory(void)
1097 {
1098 char buffer[MAX_PATH];
1099 PROCESS_INFORMATION info;
1100 STARTUPINFOA startup;
1101 char windir[MAX_PATH];
1102 static CHAR cmdline[] = "winver.exe";
1103
1104 memset(&startup, 0, sizeof(startup));
1105 startup.cb = sizeof(startup);
1106 startup.dwFlags = STARTF_USESHOWWINDOW;
1107 startup.wShowWindow = SW_SHOWNORMAL;
1108
1109 /* the basics */
1110 get_file_name(resfile);
1111 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1112 GetWindowsDirectoryA( windir, sizeof(windir) );
1113 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n");
1114 /* wait for child to terminate */
1115 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1116 /* child process has changed result file, so let profile functions know about it */
1117 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1118 CloseHandle(info.hThread);
1119 CloseHandle(info.hProcess);
1120
1121 okChildIString("Misc", "CurrDirA", windir);
1122 release_memory();
1123 DeleteFileA(resfile);
1124
1125 /* search PATH for the exe if directory is NULL */
1126 ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1127 ok(TerminateProcess(info.hProcess, 0), "Child process termination\n");
1128 CloseHandle(info.hThread);
1129 CloseHandle(info.hProcess);
1130
1131 /* if any directory is provided, don't search PATH, error on bad directory */
1132 SetLastError(0xdeadbeef);
1133 memset(&info, 0, sizeof(info));
1134 ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L,
1135 NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n");
1136 ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1137 ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n");
1138 }
1139
1140 static void test_Toolhelp(void)
1141 {
1142 char buffer[MAX_PATH];
1143 STARTUPINFOA startup;
1144 PROCESS_INFORMATION info;
1145 HANDLE process, thread, snapshot;
1146 PROCESSENTRY32 pe;
1147 THREADENTRY32 te;
1148 DWORD ret;
1149 int i;
1150
1151 memset(&startup, 0, sizeof(startup));
1152 startup.cb = sizeof(startup);
1153 startup.dwFlags = STARTF_USESHOWWINDOW;
1154 startup.wShowWindow = SW_SHOWNORMAL;
1155
1156 get_file_name(resfile);
1157 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1158 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1159 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1160 CloseHandle(info.hProcess);
1161 CloseHandle(info.hThread);
1162
1163 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1164 okChildInt("Toolhelp", "cntUsage", 0);
1165 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1166 okChildInt("Toolhelp", "th32ModuleID", 0);
1167 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1168 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1169 okChildInt("Toolhelp", "dwFlags", 0);
1170
1171 release_memory();
1172 DeleteFileA(resfile);
1173
1174 get_file_name(resfile);
1175 sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile);
1176 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1177 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1178
1179 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1180 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1181 CloseHandle(process);
1182
1183 CloseHandle(info.hProcess);
1184 CloseHandle(info.hThread);
1185
1186 for (i = 0; i < 20; i++)
1187 {
1188 SetLastError(0xdeadbeef);
1189 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1190 ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError());
1191 if (!process) break;
1192 CloseHandle(process);
1193 Sleep(100);
1194 }
1195 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1196 ok(i < 20 || broken(i == 20), "process object not released\n");
1197
1198 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1199 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1200 memset(&pe, 0, sizeof(pe));
1201 pe.dwSize = sizeof(pe);
1202 if (pProcess32First(snapshot, &pe))
1203 {
1204 while (pe.th32ParentProcessID != info.dwProcessId)
1205 if (!pProcess32Next(snapshot, &pe)) break;
1206 }
1207 CloseHandle(snapshot);
1208 ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n");
1209
1210 process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID);
1211 ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1212
1213 snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1214 ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1215 memset(&te, 0, sizeof(te));
1216 te.dwSize = sizeof(te);
1217 if (pThread32First(snapshot, &te))
1218 {
1219 while (te.th32OwnerProcessID != pe.th32ProcessID)
1220 if (!pThread32Next(snapshot, &te)) break;
1221 }
1222 CloseHandle(snapshot);
1223 ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1224
1225 thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID);
1226 ok(thread != NULL, "OpenThread failed %u\n", GetLastError());
1227 ret = ResumeThread(thread);
1228 ok(ret == 1, "expected 1, got %u\n", ret);
1229 CloseHandle(thread);
1230
1231 ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1232 CloseHandle(process);
1233
1234 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1235 okChildInt("Toolhelp", "cntUsage", 0);
1236 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1237 okChildInt("Toolhelp", "th32ModuleID", 0);
1238 okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1239 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1240 okChildInt("Toolhelp", "dwFlags", 0);
1241
1242 release_memory();
1243 DeleteFileA(resfile);
1244 }
1245
1246 static BOOL is_str_env_drive_dir(const char* str)
1247 {
1248 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1249 str[3] == '=' && str[4] == str[1];
1250 }
1251
1252 /* compared expected child's environment (in gesA) from actual
1253 * environment our child got
1254 */
1255 static void cmpEnvironment(const char* gesA)
1256 {
1257 int i, clen;
1258 const char* ptrA;
1259 char* res;
1260 char key[32];
1261 BOOL found;
1262
1263 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1264
1265 /* now look each parent env in child */
1266 if ((ptrA = gesA) != NULL)
1267 {
1268 while (*ptrA)
1269 {
1270 for (i = 0; i < clen; i++)
1271 {
1272 sprintf(key, "env%d", i);
1273 res = getChildString("EnvironmentA", key);
1274 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1275 break;
1276 }
1277 found = i < clen;
1278 ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1279
1280 ptrA += strlen(ptrA) + 1;
1281 release_memory();
1282 }
1283 }
1284 /* and each child env in parent */
1285 for (i = 0; i < clen; i++)
1286 {
1287 sprintf(key, "env%d", i);
1288 res = getChildString("EnvironmentA", key);
1289 if ((ptrA = gesA) != NULL)
1290 {
1291 while (*ptrA)
1292 {
1293 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1294 break;
1295 ptrA += strlen(ptrA) + 1;
1296 }
1297 if (!*ptrA) ptrA = NULL;
1298 }
1299
1300 if (!is_str_env_drive_dir(res))
1301 {
1302 found = ptrA != NULL;
1303 ok(found, "Child-env string %s isn't in parent process\n", res);
1304 }
1305 /* else => should also test we get the right per drive default directory here... */
1306 }
1307 }
1308
1309 static void test_Environment(void)
1310 {
1311 char buffer[MAX_PATH];
1312 PROCESS_INFORMATION info;
1313 STARTUPINFOA startup;
1314 char *child_env;
1315 int child_env_len;
1316 char *ptr;
1317 char *ptr2;
1318 char *env;
1319 int slen;
1320
1321 memset(&startup, 0, sizeof(startup));
1322 startup.cb = sizeof(startup);
1323 startup.dwFlags = STARTF_USESHOWWINDOW;
1324 startup.wShowWindow = SW_SHOWNORMAL;
1325
1326 /* the basics */
1327 get_file_name(resfile);
1328 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1329 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1330 /* wait for child to terminate */
1331 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1332 /* child process has changed result file, so let profile functions know about it */
1333 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1334
1335 env = GetEnvironmentStringsA();
1336 cmpEnvironment(env);
1337 release_memory();
1338 DeleteFileA(resfile);
1339
1340 memset(&startup, 0, sizeof(startup));
1341 startup.cb = sizeof(startup);
1342 startup.dwFlags = STARTF_USESHOWWINDOW;
1343 startup.wShowWindow = SW_SHOWNORMAL;
1344
1345 /* the basics */
1346 get_file_name(resfile);
1347 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1348
1349 child_env_len = 0;
1350 ptr = env;
1351 while(*ptr)
1352 {
1353 slen = strlen(ptr)+1;
1354 child_env_len += slen;
1355 ptr += slen;
1356 }
1357 /* Add space for additional environment variables */
1358 child_env_len += 256;
1359 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1360
1361 ptr = child_env;
1362 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1363 ptr += strlen(ptr) + 1;
1364 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1365 ptr += strlen(ptr) + 1;
1366 strcpy(ptr, "FOO=BAR");
1367 ptr += strlen(ptr) + 1;
1368 strcpy(ptr, "BAR=FOOBAR");
1369 ptr += strlen(ptr) + 1;
1370 /* copy all existing variables except:
1371 * - WINELOADER
1372 * - PATH (already set above)
1373 * - the directory definitions (=[A-Z]:=)
1374 */
1375 for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1376 {
1377 if (strncmp(ptr2, "PATH=", 5) != 0 &&
1378 strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1379 !is_str_env_drive_dir(ptr2))
1380 {
1381 strcpy(ptr, ptr2);
1382 ptr += strlen(ptr) + 1;
1383 }
1384 }
1385 *ptr = '\0';
1386 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1387 /* wait for child to terminate */
1388 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1389 /* child process has changed result file, so let profile functions know about it */
1390 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1391
1392 cmpEnvironment(child_env);
1393
1394 HeapFree(GetProcessHeap(), 0, child_env);
1395 FreeEnvironmentStringsA(env);
1396 release_memory();
1397 DeleteFileA(resfile);
1398 }
1399
1400 static void test_SuspendFlag(void)
1401 {
1402 char buffer[MAX_PATH];
1403 PROCESS_INFORMATION info;
1404 STARTUPINFOA startup, us;
1405 DWORD exit_status;
1406 char *result;
1407
1408 /* let's start simplistic */
1409 memset(&startup, 0, sizeof(startup));
1410 startup.cb = sizeof(startup);
1411 startup.dwFlags = STARTF_USESHOWWINDOW;
1412 startup.wShowWindow = SW_SHOWNORMAL;
1413
1414 get_file_name(resfile);
1415 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1416 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1417
1418 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1419 Sleep(1000);
1420 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1421 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1422
1423 /* wait for child to terminate */
1424 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1425 /* child process has changed result file, so let profile functions know about it */
1426 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1427
1428 GetStartupInfoA(&us);
1429
1430 okChildInt("StartupInfoA", "cb", startup.cb);
1431 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1432 result = getChildString( "StartupInfoA", "lpTitle" );
1433 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1434 "expected '%s' or null, got '%s'\n", selfname, result );
1435 okChildInt("StartupInfoA", "dwX", startup.dwX);
1436 okChildInt("StartupInfoA", "dwY", startup.dwY);
1437 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1438 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1439 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1440 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1441 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1442 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1443 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1444 release_memory();
1445 DeleteFileA(resfile);
1446 }
1447
1448 static void test_DebuggingFlag(void)
1449 {
1450 char buffer[MAX_PATH];
1451 void *processbase = NULL;
1452 PROCESS_INFORMATION info;
1453 STARTUPINFOA startup, us;
1454 DEBUG_EVENT de;
1455 unsigned dbg = 0;
1456 char *result;
1457
1458 /* let's start simplistic */
1459 memset(&startup, 0, sizeof(startup));
1460 startup.cb = sizeof(startup);
1461 startup.dwFlags = STARTF_USESHOWWINDOW;
1462 startup.wShowWindow = SW_SHOWNORMAL;
1463
1464 get_file_name(resfile);
1465 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1466 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1467
1468 /* get all startup events up to the entry point break exception */
1469 do
1470 {
1471 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1472 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1473 if (!dbg)
1474 {
1475 ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1476 "first event: %d\n", de.dwDebugEventCode);
1477 processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1478 }
1479 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1480 ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT ||
1481 de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1482 } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1483
1484 ok(dbg, "I have seen a debug event\n");
1485 /* wait for child to terminate */
1486 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1487 /* child process has changed result file, so let profile functions know about it */
1488 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1489
1490 GetStartupInfoA(&us);
1491
1492 okChildInt("StartupInfoA", "cb", startup.cb);
1493 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1494 result = getChildString( "StartupInfoA", "lpTitle" );
1495 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1496 "expected '%s' or null, got '%s'\n", selfname, result );
1497 okChildInt("StartupInfoA", "dwX", startup.dwX);
1498 okChildInt("StartupInfoA", "dwY", startup.dwY);
1499 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1500 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1501 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1502 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1503 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1504 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1505 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1506 release_memory();
1507 DeleteFileA(resfile);
1508 }
1509
1510 static BOOL is_console(HANDLE h)
1511 {
1512 return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1513 }
1514
1515 static void test_Console(void)
1516 {
1517 char buffer[MAX_PATH];
1518 PROCESS_INFORMATION info;
1519 STARTUPINFOA startup, us;
1520 SECURITY_ATTRIBUTES sa;
1521 CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC;
1522 DWORD modeIn, modeOut, modeInC, modeOutC;
1523 DWORD cpIn, cpOut, cpInC, cpOutC;
1524 DWORD w;
1525 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1526 const char* msg = "This is a std-handle inheritance test.";
1527 unsigned msg_len;
1528 BOOL run_tests = TRUE;
1529 char *result;
1530
1531 memset(&startup, 0, sizeof(startup));
1532 startup.cb = sizeof(startup);
1533 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1534 startup.wShowWindow = SW_SHOWNORMAL;
1535
1536 sa.nLength = sizeof(sa);
1537 sa.lpSecurityDescriptor = NULL;
1538 sa.bInheritHandle = TRUE;
1539
1540 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1541 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1542
1543 /* first, we need to be sure we're attached to a console */
1544 if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1545 {
1546 /* we're not attached to a console, let's do it */
1547 AllocConsole();
1548 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1549 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1550 }
1551 /* now verify everything's ok */
1552 ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1553 ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1554 startup.hStdError = startup.hStdOutput;
1555
1556 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1557 ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1558 ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1559 cpIn = GetConsoleCP();
1560 cpOut = GetConsoleOutputCP();
1561
1562 get_file_name(resfile);
1563 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile);
1564 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1565
1566 /* wait for child to terminate */
1567 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1568 /* child process has changed result file, so let profile functions know about it */
1569 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1570
1571 /* now get the modification the child has made, and resets parents expected values */
1572 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1573 ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1574 ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1575
1576 SetConsoleMode(startup.hStdInput, modeIn);
1577 SetConsoleMode(startup.hStdOutput, modeOut);
1578
1579 cpInC = GetConsoleCP();
1580 cpOutC = GetConsoleOutputCP();
1581
1582 /* Try to set invalid CP */
1583 SetLastError(0xdeadbeef);
1584 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1585 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1586 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1587 "GetLastError: expecting %u got %u\n",
1588 ERROR_INVALID_PARAMETER, GetLastError());
1589 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1590 run_tests = FALSE;
1591
1592
1593 SetLastError(0xdeadbeef);
1594 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1595 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1596 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1597 "GetLastError: expecting %u got %u\n",
1598 ERROR_INVALID_PARAMETER, GetLastError());
1599
1600 SetConsoleCP(cpIn);
1601 SetConsoleOutputCP(cpOut);
1602
1603 GetStartupInfoA(&us);
1604
1605 okChildInt("StartupInfoA", "cb", startup.cb);
1606 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1607 result = getChildString( "StartupInfoA", "lpTitle" );
1608 ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1609 "expected '%s' or null, got '%s'\n", selfname, result );
1610 okChildInt("StartupInfoA", "dwX", startup.dwX);
1611 okChildInt("StartupInfoA", "dwY", startup.dwY);
1612 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1613 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1614 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1615 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1616 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1617 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1618 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1619
1620 /* check child correctly inherited the console */
1621 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1622 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1623 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1624 okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1625 okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1626 okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1627 okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1628 okChildInt("Console", "Attributes", sbi.wAttributes);
1629 okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1630 okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1631 okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1632 okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1633 okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1634 okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1635 okChildInt("Console", "InputCP", cpIn);
1636 okChildInt("Console", "OutputCP", cpOut);
1637 okChildInt("Console", "InputMode", modeIn);
1638 okChildInt("Console", "OutputMode", modeOut);
1639
1640 if (run_tests)
1641 {
1642 ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1643 ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1644 }
1645 else
1646 win_skip("Setting the codepage is not implemented\n");
1647
1648 ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1649 ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1650 trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1651 ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1652
1653 release_memory();
1654 DeleteFileA(resfile);
1655
1656 ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1657 ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(),
1658 &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1659 "Duplicating as inheritable child-output pipe\n");
1660 CloseHandle(hChildOut);
1661
1662 ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1663 ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(),
1664 &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1665 "Duplicating as inheritable child-input pipe\n");
1666 CloseHandle(hChildIn);
1667
1668 memset(&startup, 0, sizeof(startup));
1669 startup.cb = sizeof(startup);
1670 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1671 startup.wShowWindow = SW_SHOWNORMAL;
1672 startup.hStdInput = hChildInInh;
1673 startup.hStdOutput = hChildOutInh;
1674 startup.hStdError = hChildOutInh;
1675
1676 get_file_name(resfile);
1677 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile);
1678 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1679 ok(CloseHandle(hChildInInh), "Closing handle\n");
1680 ok(CloseHandle(hChildOutInh), "Closing handle\n");
1681
1682 msg_len = strlen(msg) + 1;
1683 ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1684 ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1685 memset(buffer, 0, sizeof(buffer));
1686 ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1687 ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1688
1689 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1690 ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1691
1692 /* wait for child to terminate */
1693 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1694 /* child process has changed result file, so let profile functions know about it */
1695 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1696
1697 okChildString("StdHandle", "msg", msg);
1698
1699 release_memory();
1700 DeleteFileA(resfile);
1701 }
1702
1703 static void test_ExitCode(void)
1704 {
1705 char buffer[MAX_PATH];
1706 PROCESS_INFORMATION info;
1707 STARTUPINFOA startup;
1708 DWORD code;
1709
1710 /* let's start simplistic */
1711 memset(&startup, 0, sizeof(startup));
1712 startup.cb = sizeof(startup);
1713 startup.dwFlags = STARTF_USESHOWWINDOW;
1714 startup.wShowWindow = SW_SHOWNORMAL;
1715
1716 get_file_name(resfile);
1717 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile);
1718 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1719
1720 /* wait for child to terminate */
1721 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1722 /* child process has changed result file, so let profile functions know about it */
1723 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1724
1725 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1726 okChildInt("ExitCode", "value", code);
1727
1728 release_memory();
1729 DeleteFileA(resfile);
1730 }
1731
1732 static void test_OpenProcess(void)
1733 {
1734 HANDLE hproc;
1735 void *addr1;
1736 MEMORY_BASIC_INFORMATION info;
1737 SIZE_T dummy, read_bytes;
1738 BOOL ret;
1739
1740 /* not exported in all windows versions */
1741 if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1742 win_skip("VirtualAllocEx not found\n");
1743 return;
1744 }
1745
1746 /* without PROCESS_VM_OPERATION */
1747 hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1748 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1749
1750 SetLastError(0xdeadbeef);
1751 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1752 ok(!addr1, "VirtualAllocEx should fail\n");
1753 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1754 { /* Win9x */
1755 CloseHandle(hproc);
1756 win_skip("VirtualAllocEx not implemented\n");
1757 return;
1758 }
1759 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1760
1761 read_bytes = 0xdeadbeef;
1762 SetLastError(0xdeadbeef);
1763 ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes);
1764 ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1765 ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1766
1767 CloseHandle(hproc);
1768
1769 hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1770 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1771
1772 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1773 ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1774
1775 /* without PROCESS_QUERY_INFORMATION */
1776 SetLastError(0xdeadbeef);
1777 ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1778 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1779 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1780
1781 /* without PROCESS_VM_READ */
1782 read_bytes = 0xdeadbeef;
1783 SetLastError(0xdeadbeef);
1784 ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1785 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1786 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1787 ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1788
1789 CloseHandle(hproc);
1790
1791 hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1792
1793 memset(&info, 0xcc, sizeof(info));
1794 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1795 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1796
1797 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1798 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1799 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1800 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1801 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1802 /* NT reports Protect == 0 for a not committed memory block */
1803 ok(info.Protect == 0 /* NT */ ||
1804 info.Protect == PAGE_NOACCESS, /* Win9x */
1805 "%x != PAGE_NOACCESS\n", info.Protect);
1806 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1807
1808 SetLastError(0xdeadbeef);
1809 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1810 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1811 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1812
1813 CloseHandle(hproc);
1814
1815 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1816 if (hproc)
1817 {
1818 SetLastError(0xdeadbeef);
1819 memset(&info, 0xcc, sizeof(info));
1820 read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1821 if (read_bytes) /* win8 */
1822 {
1823 ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1824 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1825 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1826 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1827 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1828 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1829 ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
1830 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1831 }
1832 else /* before win8 */
1833 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1834
1835 SetLastError(0xdeadbeef);
1836 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1837 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1838 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1839
1840 CloseHandle(hproc);
1841 }
1842
1843 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1844 }
1845
1846 static void test_GetProcessVersion(void)
1847 {
1848 static char cmdline[] = "winver.exe";
1849 PROCESS_INFORMATION pi;
1850 STARTUPINFOA si;
1851 DWORD ret;
1852
1853 SetLastError(0xdeadbeef);
1854 ret = GetProcessVersion(0);
1855 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1856
1857 SetLastError(0xdeadbeef);
1858 ret = GetProcessVersion(GetCurrentProcessId());
1859 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1860
1861 memset(&si, 0, sizeof(si));
1862 si.cb = sizeof(si);
1863 si.dwFlags = STARTF_USESHOWWINDOW;
1864 si.wShowWindow = SW_HIDE;
1865 SetLastError(0xdeadbeef);
1866 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1867 ok(ret, "CreateProcess error %u\n", GetLastError());
1868
1869 SetLastError(0xdeadbeef);
1870 ret = GetProcessVersion(pi.dwProcessId);
1871 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1872
1873 SetLastError(0xdeadbeef);
1874 ret = TerminateProcess(pi.hProcess, 0);
1875 ok(ret, "TerminateProcess error %u\n", GetLastError());
1876
1877 CloseHandle(pi.hProcess);
1878 CloseHandle(pi.hThread);
1879 }
1880
1881 static void test_GetProcessImageFileNameA(void)
1882 {
1883 DWORD rc;
1884 CHAR process[MAX_PATH];
1885 static const char harddisk[] = "\\Device\\HarddiskVolume";
1886
1887 if (!pK32GetProcessImageFileNameA)
1888 {
1889 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1890 return;
1891 }
1892
1893 /* callers must guess the buffer size */
1894 SetLastError(0xdeadbeef);
1895 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1896 ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1897 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError());
1898
1899 *process = '\0';
1900 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1901 expect_eq_d(rc, lstrlenA(process));
1902 if (strncmp(process, harddisk, lstrlenA(harddisk)))
1903 {
1904 todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1905 return;
1906 }
1907
1908 if (!pQueryFullProcessImageNameA)
1909 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1910 else
1911 {
1912 CHAR image[MAX_PATH];
1913 DWORD length;
1914
1915 length = sizeof(image);
1916 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1917 expect_eq_d(length, lstrlenA(image));
1918 ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1919 }
1920 }
1921
1922 static void test_QueryFullProcessImageNameA(void)
1923 {
1924 #define INIT_STR "Just some words"
1925 DWORD length, size;
1926 CHAR buf[MAX_PATH], module[MAX_PATH];
1927
1928 if (!pQueryFullProcessImageNameA)
1929 {
1930 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1931 return;
1932 }
1933
1934 *module = '\0';
1935 SetLastError(0); /* old Windows don't reset it on success */
1936 size = GetModuleFileNameA(NULL, module, sizeof(module));
1937 ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError());
1938
1939 /* get the buffer length without \0 terminator */
1940 length = sizeof(buf);
1941 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1942 expect_eq_d(length, lstrlenA(buf));
1943 ok((buf[0] == '\\' && buf[1] == '\\') ||
1944 lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1945
1946 /* when the buffer is too small
1947 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1948 * - the size variable is not modified
1949 * tested with the biggest too small size
1950 */
1951 size = length;
1952 sprintf(buf,INIT_STR);
1953 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1954 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1955 expect_eq_d(length, size);
1956 expect_eq_s(INIT_STR, buf);
1957
1958 /* retest with smaller buffer size
1959 */
1960 size = 4;
1961 sprintf(buf,INIT_STR);
1962 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1963 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1964 expect_eq_d(4, size);
1965 expect_eq_s(INIT_STR, buf);
1966
1967 /* this is a difference between the ascii and the unicode version
1968 * the unicode version crashes when the size is big enough to hold
1969 * the result while the ascii version throws an error
1970 */
1971 size = 1024;
1972 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1973 expect_eq_d(1024, size);
1974 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
1975 }
1976
1977 static void test_QueryFullProcessImageNameW(void)
1978 {
1979 HANDLE hSelf;
1980 WCHAR module_name[1024], device[1024];
1981 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
1982 WCHAR buf[1024];
1983 DWORD size, len;
1984
1985 if (!pQueryFullProcessImageNameW)
1986 {
1987 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1988 return;
1989 }
1990
1991 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1992
1993 /* GetCurrentProcess pseudo-handle */
1994 size = sizeof(buf) / sizeof(buf[0]);
1995 expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
1996 expect_eq_d(lstrlenW(buf), size);
1997 expect_eq_ws_i(buf, module_name);
1998
1999 hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
2000 /* Real handle */
2001 size = sizeof(buf) / sizeof(buf[0]);
2002 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2003 expect_eq_d(lstrlenW(buf), size);
2004 expect_eq_ws_i(buf, module_name);
2005
2006 /* Buffer too small */
2007 size = lstrlenW(module_name)/2;
2008 lstrcpyW(buf, deviceW);
2009 SetLastError(0xdeadbeef);
2010 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2011 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2012 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2013 expect_eq_ws_i(deviceW, buf); /* buffer not changed */
2014
2015 /* Too small - not space for NUL terminator */
2016 size = lstrlenW(module_name);
2017 SetLastError(0xdeadbeef);
2018 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2019 expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
2020 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2021
2022 /* NULL buffer */
2023 size = 0;
2024 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
2025 expect_eq_d(0, size);
2026 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2027
2028 /* Buffer too small */
2029 size = lstrlenW(module_name)/2;
2030 SetLastError(0xdeadbeef);
2031 lstrcpyW(buf, module_name);
2032 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2033 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
2034 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2035 expect_eq_ws_i(module_name, buf); /* buffer not changed */
2036
2037
2038 /* native path */
2039 size = sizeof(buf) / sizeof(buf[0]);
2040 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2041 expect_eq_d(lstrlenW(buf), size);
2042 ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2043 ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2044
2045 module_name[2] = '\0';
2046 *device = '\0';
2047 size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0]));
2048 ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2049 len = lstrlenW(device);
2050 ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2051
2052 if (size >= lstrlenW(buf))
2053 {
2054 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2055 }
2056 else
2057 {
2058 ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2059 buf[len] = '\0';
2060 ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2061 ok(lstrcmpiW(module_name+3, buf+len+1) == 0, "expected '%s' to match '%s'\n", wine_dbgstr_w(module_name+3), wine_dbgstr_w(buf+len+1));
2062 }
2063
2064 CloseHandle(hSelf);
2065 }
2066
2067 static void test_Handles(void)
2068 {
2069 HANDLE handle = GetCurrentProcess();
2070 HANDLE h2, h3;
2071 BOOL ret;
2072 DWORD code;
2073
2074 ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2075 handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2076 "invalid current process handle %p\n", handle );
2077 ret = GetExitCodeProcess( handle, &code );
2078 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2079 #ifdef _WIN64
2080 /* truncated handle */
2081 SetLastError( 0xdeadbeef );
2082 handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2083 ret = GetExitCodeProcess( handle, &code );
2084 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2085 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2086 /* sign-extended handle */
2087 SetLastError( 0xdeadbeef );
2088 handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle);
2089 ret = GetExitCodeProcess( handle, &code );
2090 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2091 /* invalid high-word */
2092 SetLastError( 0xdeadbeef );
2093 handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2094 ret = GetExitCodeProcess( handle, &code );
2095 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2096 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2097 #endif
2098
2099 handle = GetStdHandle( STD_ERROR_HANDLE );
2100 ok( handle != 0, "handle %p\n", handle );
2101 DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &h3,
2102 0, TRUE, DUPLICATE_SAME_ACCESS );
2103 SetStdHandle( STD_ERROR_HANDLE, h3 );
2104 CloseHandle( (HANDLE)STD_ERROR_HANDLE );
2105 h2 = GetStdHandle( STD_ERROR_HANDLE );
2106 ok( h2 == 0 ||
2107 broken( h2 == h3) || /* nt4, w2k */
2108 broken( h2 == INVALID_HANDLE_VALUE), /* win9x */
2109 "wrong handle %p/%p\n", h2, h3 );
2110 SetStdHandle( STD_ERROR_HANDLE, handle );
2111 }
2112
2113 static void test_IsWow64Process(void)
2114 {
2115 PROCESS_INFORMATION pi;
2116 STARTUPINFOA si;
2117 DWORD ret;
2118 BOOL is_wow64;
2119 static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2120 static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2121
2122 if (!pIsWow64Process)
2123 {
2124 skip("IsWow64Process is not available\n");
2125 return;
2126 }
2127
2128 memset(&si, 0, sizeof(si));
2129 si.cb = sizeof(si);
2130 si.dwFlags = STARTF_USESHOWWINDOW;
2131 si.wShowWindow = SW_HIDE;
2132 ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2133 if (ret)
2134 {
2135 trace("Created process %s\n", cmdline_wow64);
2136 is_wow64 = FALSE;
2137 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2138 ok(ret, "IsWow64Process failed.\n");
2139 ok(is_wow64, "is_wow64 returned FALSE.\n");
2140
2141 ret = TerminateProcess(pi.hProcess, 0);
2142 ok(ret, "TerminateProcess error\n");
2143
2144 CloseHandle(pi.hProcess);
2145 CloseHandle(pi.hThread);
2146 }
2147
2148 memset(&si, 0, sizeof(si));
2149 si.cb = sizeof(si);
2150 si.dwFlags = STARTF_USESHOWWINDOW;
2151 si.wShowWindow = SW_HIDE;
2152 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2153 if (ret)
2154 {
2155 trace("Created process %s\n", cmdline);
2156 is_wow64 = TRUE;
2157 ret = pIsWow64Process(pi.hProcess, &is_wow64);
2158 ok(ret, "IsWow64Process failed.\n");
2159 ok(!is_wow64, "is_wow64 returned TRUE.\n");
2160
2161 ret = TerminateProcess(pi.hProcess, 0);
2162 ok(ret, "TerminateProcess error\n");
2163
2164 CloseHandle(pi.hProcess);
2165 CloseHandle(pi.hThread);
2166 }
2167 }
2168
2169 static void test_SystemInfo(void)
2170 {
2171 SYSTEM_INFO si, nsi;
2172 BOOL is_wow64;
2173
2174 if (!pGetNativeSystemInfo)
2175 {
2176 win_skip("GetNativeSystemInfo is not available\n");
2177 return;
2178 }
2179
2180 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2181
2182 GetSystemInfo(&si);
2183 pGetNativeSystemInfo(&nsi);
2184 if (is_wow64)
2185 {
2186 if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2187 {
2188 ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2189 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2190 S(U(nsi)).wProcessorArchitecture);
2191 ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664,
2192 "Expected PROCESSOR_AMD_X8664, got %d\n",
2193 nsi.dwProcessorType);
2194 }
2195 }
2196 else
2197 {
2198 ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2199 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2200 S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2201 ok(si.dwProcessorType == nsi.dwProcessorType,
2202 "Expected no difference for dwProcessorType, got %d and %d\n",
2203 si.dwProcessorType, nsi.dwProcessorType);
2204 }
2205 }
2206
2207 static void test_RegistryQuota(void)
2208 {
2209 BOOL ret;
2210 DWORD max_quota, used_quota;
2211
2212 if (!pGetSystemRegistryQuota)
2213 {
2214 win_skip("GetSystemRegistryQuota is not available\n");
2215 return;
2216 }
2217
2218 ret = pGetSystemRegistryQuota(NULL, NULL);
2219 ok(ret == TRUE,
2220 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2221
2222 ret = pGetSystemRegistryQuota(&max_quota, NULL);
2223 ok(ret == TRUE,
2224 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2225
2226 ret = pGetSystemRegistryQuota(NULL, &used_quota);
2227 ok(ret == TRUE,
2228 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2229
2230 ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2231 ok(ret == TRUE,
2232 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2233 }
2234
2235 static void test_TerminateProcess(void)
2236 {
2237 static char cmdline[] = "winver.exe";
2238 PROCESS_INFORMATION pi;
2239 STARTUPINFOA si;
2240 DWORD ret;
2241 HANDLE dummy, thread;
2242
2243 memset(&si, 0, sizeof(si));
2244 si.cb = sizeof(si);
2245 SetLastError(0xdeadbeef);
2246 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2247 ok(ret, "CreateProcess error %u\n", GetLastError());
2248
2249 SetLastError(0xdeadbeef);
2250 thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2251 ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2252
2253 /* create a not closed thread handle duplicate in the target process */
2254 SetLastError(0xdeadbeef);
2255 ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy,
2256 0, FALSE, DUPLICATE_SAME_ACCESS);
2257 ok(ret, "DuplicateHandle error %u\n", GetLastError());
2258
2259 SetLastError(0xdeadbeef);
2260 ret = TerminateThread(thread, 0);
2261 ok(ret, "TerminateThread error %u\n", GetLastError());
2262 CloseHandle(thread);
2263
2264 SetLastError(0xdeadbeef);
2265 ret = TerminateProcess(pi.hProcess, 0);
2266 ok(ret, "TerminateProcess error %u\n", GetLastError());
2267
2268 CloseHandle(pi.hProcess);
2269 CloseHandle(pi.hThread);
2270 }
2271
2272 static void test_DuplicateHandle(void)
2273 {
2274 char path[MAX_PATH], file_name[MAX_PATH];
2275 HANDLE f, fmin, out;
2276 DWORD info;
2277 BOOL r;
2278
2279 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2280 GetCurrentProcess(), &out, 0, FALSE,
2281 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2282 ok(r, "DuplicateHandle error %u\n", GetLastError());
2283 r = GetHandleInformation(out, &info);
2284 ok(r, "GetHandleInformation error %u\n", GetLastError());
2285 ok(info == 0, "info = %x\n", info);
2286 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2287 CloseHandle(out);
2288
2289 r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2290 GetCurrentProcess(), &out, 0, TRUE,
2291 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2292 ok(r, "DuplicateHandle error %u\n", GetLastError());
2293 r = GetHandleInformation(out, &info);
2294 ok(r, "GetHandleInformation error %u\n", GetLastError());
2295 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2296 ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2297 CloseHandle(out);
2298
2299 GetTempPathA(MAX_PATH, path);
2300 GetTempFileNameA(path, "wt", 0, file_name);
2301 f = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2302 if (f == INVALID_HANDLE_VALUE)
2303 {
2304 ok(0, "could not create %s\n", file_name);
2305 return;
2306 }
2307
2308 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2309 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2310 ok(r, "DuplicateHandle error %u\n", GetLastError());
2311 ok(f == out, "f != out\n");
2312 r = GetHandleInformation(out, &info);
2313 ok(r, "GetHandleInformation error %u\n", GetLastError());
2314 ok(info == 0, "info = %x\n", info);
2315
2316 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2317 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2318 ok(r, "DuplicateHandle error %u\n", GetLastError());
2319 ok(f == out, "f != out\n");
2320 r = GetHandleInformation(out, &info);
2321 ok(r, "GetHandleInformation error %u\n", GetLastError());
2322 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2323
2324 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
2325 ok(r, "SetHandleInformation error %u\n", GetLastError());
2326 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2327 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2328 ok(r, "DuplicateHandle error %u\n", GetLastError());
2329 ok(f != out, "f == out\n");
2330 r = GetHandleInformation(out, &info);
2331 ok(r, "GetHandleInformation error %u\n", GetLastError());
2332 ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2333 r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2334 ok(r, "SetHandleInformation error %u\n", GetLastError());
2335
2336 /* Test if DuplicateHandle allocates first free handle */
2337 if (f > out)
2338 {
2339 fmin = out;
2340 }
2341 else
2342 {
2343 fmin = f;
2344 f = out;
2345 }
2346 CloseHandle(fmin);
2347 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2348 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2349 ok(r, "DuplicateHandle error %u\n", GetLastError());
2350 ok(f == out, "f != out\n");
2351 CloseHandle(out);
2352 DeleteFileA(file_name);
2353
2354 f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2355 if (!is_console(f))
2356 {
2357 skip("DuplicateHandle on console handle\n");
2358 CloseHandle(f);
2359 return;
2360 }
2361
2362 r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2363 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2364 ok(r, "DuplicateHandle error %u\n", GetLastError());
2365 todo_wine ok(f != out, "f == out\n");
2366 CloseHandle(out);
2367 }
2368
2369 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2370 static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2371 {
2372 LPOVERLAPPED overlapped;
2373 ULONG_PTR value;
2374 DWORD key;
2375 BOOL ret;
2376
2377 ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait);
2378
2379 ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
2380 if (ret)
2381 {
2382 ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key);
2383 ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2384 ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2385 }
2386 }
2387
2388 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2389 static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2390 {
2391 BOOL ret;
2392 char buffer[MAX_PATH];
2393 STARTUPINFOA si = {0};
2394
2395 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command);
2396
2397 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2398 ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError());
2399 }
2400
2401 #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
2402 static void _test_assigned_proc(int line, HANDLE job, int expected_count, ...)
2403 {
2404 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20];
2405 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2406 DWORD ret_len, pid;
2407 va_list valist;
2408 int n;
2409 BOOL ret;
2410
2411 memset(buf, 0, sizeof(buf));
2412 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2413 ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2414 if (ret)
2415 {
2416 todo_wine_if(expected_count)
2417 ok_(__FILE__, line)(expected_count == pid_list->NumberOfAssignedProcesses,
2418 "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n",
2419 expected_count, pid_list->NumberOfAssignedProcesses);
2420 todo_wine_if(expected_count)
2421 ok_(__FILE__, line)(expected_count == pid_list->NumberOfProcessIdsInList,
2422 "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n",
2423 expected_count, pid_list->NumberOfProcessIdsInList);
2424
2425 va_start(valist, expected_count);
2426 for (n = 0; n < min(expected_count, pid_list->NumberOfProcessIdsInList); ++n)
2427 {
2428 pid = va_arg(valist, DWORD);
2429 ok_(__FILE__, line)(pid == pid_list->ProcessIdList[n],
2430 "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n",
2431 n, pid, pid_list->ProcessIdList[n]);
2432 }
2433 va_end(valist);
2434 }
2435 }
2436
2437 #define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc)
2438 static void _test_accounting(int line, HANDLE job, int total_proc, int active_proc, int terminated_proc)
2439 {
2440 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting;
2441 DWORD ret_len;
2442 BOOL ret;
2443
2444 memset(&basic_accounting, 0, sizeof(basic_accounting));
2445 ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting, sizeof(basic_accounting), &ret_len);
2446 ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2447 if (ret)
2448 {
2449 /* Not going to check process times or page faults */
2450
2451 todo_wine_if(total_proc)
2452 ok_(__FILE__, line)(total_proc == basic_accounting.TotalProcesses,
2453 "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n",
2454 total_proc, basic_accounting.TotalProcesses);
2455 todo_wine_if(active_proc)
2456 ok_(__FILE__, line)(active_proc == basic_accounting.ActiveProcesses,
2457 "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n",
2458 active_proc, basic_accounting.ActiveProcesses);
2459 ok_(__FILE__, line)(terminated_proc == basic_accounting.TotalTerminatedProcesses,
2460 "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n",
2461 terminated_proc, basic_accounting.TotalTerminatedProcesses);
2462 }
2463 }
2464
2465 static void test_IsProcessInJob(void)
2466 {
2467 HANDLE job, job2;
2468 PROCESS_INFORMATION pi;
2469 BOOL ret, out;
2470 DWORD dwret;
2471
2472 if (!pIsProcessInJob)
2473 {
2474 win_skip("IsProcessInJob not available.\n");
2475 return;
2476 }
2477
2478 job = pCreateJobObjectW(NULL, NULL);
2479 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2480
2481 job2 = pCreateJobObjectW(NULL, NULL);
2482 ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError());
2483
2484 create_process("wait", &pi);
2485
2486 out = TRUE;
2487 ret = pIsProcessInJob(pi.hProcess, job, &out);
2488 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2489 ok(!out, "IsProcessInJob returned out=%u\n", out);
2490 test_assigned_proc(job, 0);
2491 test_accounting(job, 0, 0, 0);
2492
2493 out = TRUE;
2494 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2495 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2496 ok(!out, "IsProcessInJob returned out=%u\n", out);
2497 test_assigned_proc(job2, 0);
2498 test_accounting(job2, 0, 0, 0);
2499
2500 out = TRUE;
2501 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2502 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2503 ok(!out, "IsProcessInJob returned out=%u\n", out);
2504
2505 ret = pAssignProcessToJobObject(job, pi.hProcess);
2506 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2507
2508 out = FALSE;
2509 ret = pIsProcessInJob(pi.hProcess, job, &out);
2510 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2511 ok(out, "IsProcessInJob returned out=%u\n", out);
2512 test_assigned_proc(job, 1, pi.dwProcessId);
2513 test_accounting(job, 1, 1, 0);
2514
2515 out = TRUE;
2516 ret = pIsProcessInJob(pi.hProcess, job2, &out);
2517 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2518 ok(!out, "IsProcessInJob returned out=%u\n", out);
2519 test_assigned_proc(job2, 0);
2520 test_accounting(job2, 0, 0, 0);
2521
2522 out = FALSE;
2523 ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2524 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2525 ok(out, "IsProcessInJob returned out=%u\n", out);
2526
2527 TerminateProcess(pi.hProcess, 0);
2528
2529 dwret = WaitForSingleObject(pi.hProcess, 1000);
2530 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2531
2532 out = FALSE;
2533 ret = pIsProcessInJob(pi.hProcess, job, &out);
2534 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2535 ok(out, "IsProcessInJob returned out=%u\n", out);
2536 test_assigned_proc(job, 0);
2537 test_accounting(job, 1, 0, 0);
2538
2539 CloseHandle(pi.hProcess);
2540 CloseHandle(pi.hThread);
2541 CloseHandle(job);
2542 CloseHandle(job2);
2543 }
2544
2545 static void test_TerminateJobObject(void)
2546 {
2547 HANDLE job;
2548 PROCESS_INFORMATION pi;
2549 BOOL ret;
2550 DWORD dwret;
2551
2552 job = pCreateJobObjectW(NULL, NULL);
2553 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2554 test_assigned_proc(job, 0);
2555 test_accounting(job, 0, 0, 0);
2556
2557 create_process("wait", &pi);
2558
2559 ret = pAssignProcessToJobObject(job, pi.hProcess);
2560 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2561 test_assigned_proc(job, 1, pi.dwProcessId);
2562 test_accounting(job, 1, 1, 0);
2563
2564 ret = pTerminateJobObject(job, 123);
2565 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2566
2567 dwret = WaitForSingleObject(pi.hProcess, 1000);
2568 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2569 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2570 test_assigned_proc(job, 0);
2571 test_accounting(job, 1, 0, 0);
2572
2573 ret = GetExitCodeProcess(pi.hProcess, &dwret);
2574 ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
2575 ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */,
2576 "wrong exitcode %u\n", dwret);
2577
2578 CloseHandle(pi.hProcess);
2579 CloseHandle(pi.hThread);
2580
2581 /* Test adding an already terminated process to a job object */
2582 create_process("exit", &pi);
2583
2584 dwret = WaitForSingleObject(pi.hProcess, 1000);
2585 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2586
2587 SetLastError(0xdeadbeef);
2588 ret = pAssignProcessToJobObject(job, pi.hProcess);
2589 ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2590 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2591 test_assigned_proc(job, 0);
2592 test_accounting(job, 1, 0, 0);
2593
2594 CloseHandle(pi.hProcess);
2595 CloseHandle(pi.hThread);
2596
2597 CloseHandle(job);
2598 }
2599
2600 static void test_QueryInformationJobObject(void)
2601 {
2602 char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2603 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2604 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2605 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2606 DWORD dwret, ret_len;
2607 PROCESS_INFORMATION pi[2];
2608 HANDLE job;
2609 BOOL ret;
2610
2611 job = pCreateJobObjectW(NULL, NULL);
2612 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2613
2614 /* Only active processes are returned */
2615 create_process("exit", &pi[0]);
2616 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2617 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2618 dwret = WaitForSingleObject(pi[0].hProcess, 1000);
2619 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2620
2621 CloseHandle(pi[0].hProcess);
2622 CloseHandle(pi[0].hThread);
2623
2624 create_process("wait", &pi[0]);
2625 ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2626 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2627
2628 create_process("wait", &pi[1]);
2629 ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2630 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2631
2632 SetLastError(0xdeadbeef);
2633 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2634 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len);
2635 ok(!ret, "QueryInformationJobObject expected failure\n");
2636 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2637
2638 SetLastError(0xdeadbeef);
2639 memset(buf, 0, sizeof(buf));
2640 pid_list->NumberOfAssignedProcesses = 42;
2641 pid_list->NumberOfProcessIdsInList = 42;
2642 ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2643 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len);
2644 todo_wine
2645 ok(!ret, "QueryInformationJobObject expected failure\n");
2646 todo_wine
2647 expect_eq_d(ERROR_MORE_DATA, GetLastError());
2648 if (ret)
2649 {
2650 todo_wine
2651 expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2652 todo_wine
2653 expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2654 }
2655
2656 memset(buf, 0, sizeof(buf));
2657 ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2658 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2659 if(ret)
2660 {
2661 if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2662 win_skip("Number of assigned processes broken on Win 8\n");
2663 else
2664 {
2665 ULONG_PTR *list = pid_list->ProcessIdList;
2666
2667 todo_wine
2668 ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]),
2669 "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2670
2671 todo_wine
2672 expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2673 todo_wine
2674 expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2675 todo_wine
2676 expect_eq_d(pi[0].dwProcessId, list[0]);
2677 todo_wine
2678 expect_eq_d(pi[1].dwProcessId, list[1]);
2679 }
2680 }
2681
2682 /* test JobObjectBasicLimitInformation */
2683 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2684 sizeof(*basic_limit_info) - 1, &ret_len);
2685 ok(!ret, "QueryInformationJobObject expected failure\n");
2686 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2687
2688 ret_len = 0xdeadbeef;
2689 memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2690 ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2691 sizeof(*basic_limit_info), &ret_len);
2692 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2693 ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2694 expect_eq_d(0, basic_limit_info->LimitFlags);
2695
2696 /* test JobObjectExtendedLimitInformation */
2697 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2698 sizeof(ext_limit_info) - 1, &ret_len);
2699 ok(!ret, "QueryInformationJobObject expected failure\n");
2700 expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2701
2702 ret_len = 0xdeadbeef;
2703 memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2704 ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2705 sizeof(ext_limit_info), &ret_len);
2706 ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2707 ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2708 expect_eq_d(0, basic_limit_info->LimitFlags);
2709
2710 TerminateProcess(pi[0].hProcess, 0);
2711 CloseHandle(pi[0].hProcess);
2712 CloseHandle(pi[0].hThread);
2713
2714 TerminateProcess(pi[1].hProcess, 0);
2715 CloseHandle(pi[1].hProcess);
2716 CloseHandle(pi[1].hThread);
2717
2718 CloseHandle(job);
2719 }
2720
2721 static void test_CompletionPort(void)
2722 {
2723 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
2724 PROCESS_INFORMATION pi;
2725 HANDLE job, port;
2726 DWORD dwret;
2727 BOOL ret;
2728
2729 job = pCreateJobObjectW(NULL, NULL);
2730 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2731
2732 port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2733 ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
2734
2735 port_info.CompletionKey = job;
2736 port_info.CompletionPort = port;
2737 ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2738 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2739
2740 create_process("wait", &pi);
2741
2742 ret = pAssignProcessToJobObject(job, pi.hProcess);
2743 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2744
2745 test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2746
2747 TerminateProcess(pi.hProcess, 0);
2748 dwret = WaitForSingleObject(pi.hProcess, 1000);
2749 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2750
2751 test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2752 test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100);
2753
2754 CloseHandle(pi.hProcess);
2755 CloseHandle(pi.hThread);
2756 CloseHandle(job);
2757 CloseHandle(port);
2758 }
2759
2760 static void test_KillOnJobClose(void)
2761 {
2762 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2763 PROCESS_INFORMATION pi;
2764 DWORD dwret;
2765 HANDLE job;
2766 BOOL ret;
2767
2768 job = pCreateJobObjectW(NULL, NULL);
2769 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2770
2771 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
2772 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2773 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2774 {
2775 win_skip("Kill on job close limit not available\n");
2776 return;
2777 }
2778 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2779 test_assigned_proc(job, 0);
2780 test_accounting(job, 0, 0, 0);
2781
2782 create_process("wait", &pi);
2783
2784 ret = pAssignProcessToJobObject(job, pi.hProcess);
2785 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2786 test_assigned_proc(job, 1, pi.dwProcessId);
2787 test_accounting(job, 1, 1, 0);
2788
2789 CloseHandle(job);
2790
2791 dwret = WaitForSingleObject(pi.hProcess, 1000);
2792 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2793 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2794
2795 CloseHandle(pi.hProcess);
2796 CloseHandle(pi.hThread);
2797 }
2798
2799 static void test_WaitForJobObject(void)
2800 {
2801 HANDLE job;
2802 PROCESS_INFORMATION pi;
2803 BOOL ret;
2804 DWORD dwret;
2805
2806 /* test waiting for a job object when the process is killed */
2807 job = pCreateJobObjectW(NULL, NULL);
2808 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2809
2810 dwret = WaitForSingleObject(job, 100);
2811 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2812
2813 create_process("wait", &pi);
2814
2815 ret = pAssignProcessToJobObject(job, pi.hProcess);
2816 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2817
2818 dwret = WaitForSingleObject(job, 100);
2819 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2820
2821 ret = pTerminateJobObject(job, 123);
2822 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2823
2824 dwret = WaitForSingleObject(job, 500);
2825 ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2826 "WaitForSingleObject returned %u\n", dwret);
2827
2828 if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2829 {
2830 #ifdef __REACTOS__
2831 if (!ret)
2832 {
2833 ok(0, "HACK: Killing process to speed up the test\n");
2834 TerminateProcess(pi.hProcess, 0);
2835 }
2836 #endif
2837 CloseHandle(pi.hProcess);
2838 CloseHandle(pi.hThread);
2839 CloseHandle(job);
2840 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2841 return;
2842 }
2843
2844 /* the object is not reset immediately */
2845 dwret = WaitForSingleObject(job, 100);
2846 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2847
2848 CloseHandle(pi.hProcess);
2849 CloseHandle(pi.hThread);
2850
2851 /* creating a new process doesn't reset the signalled state */
2852 create_process("wait", &pi);
2853
2854 ret = pAssignProcessToJobObject(job, pi.hProcess);
2855 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2856
2857 dwret = WaitForSingleObject(job, 100);
2858 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2859
2860 ret = pTerminateJobObject(job, 123);
2861 ok(ret, "TerminateJobObject error %u\n", GetLastError());
2862
2863 CloseHandle(pi.hProcess);
2864 CloseHandle(pi.hThread);
2865
2866 CloseHandle(job);
2867
2868 /* repeat the test, but this time the process terminates properly */
2869 job = pCreateJobObjectW(NULL, NULL);
2870 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2871
2872 dwret = WaitForSingleObject(job, 100);
2873 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2874
2875 create_process("exit", &pi);
2876
2877 ret = pAssignProcessToJobObject(job, pi.hProcess);
2878 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2879
2880 dwret = WaitForSingleObject(job, 100);
2881 ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2882
2883 CloseHandle(pi.hProcess);
2884 CloseHandle(pi.hThread);
2885 CloseHandle(job);
2886 }
2887
2888 static HANDLE test_AddSelfToJob(void)
2889 {
2890 HANDLE job;
2891 BOOL ret;
2892
2893 job = pCreateJobObjectW(NULL, NULL);
2894 ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2895
2896 ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2897 ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2898 test_assigned_proc(job, 1, GetCurrentProcessId());
2899 test_accounting(job, 1, 1, 0);
2900
2901 return job;
2902 }
2903
2904 static void test_jobInheritance(HANDLE job)
2905 {
2906 char buffer[MAX_PATH];
2907 PROCESS_INFORMATION pi;
2908 STARTUPINFOA si = {0};
2909 DWORD dwret;
2910 BOOL ret, out;
2911
2912 if (!pIsProcessInJob)
2913 {
2914 win_skip("IsProcessInJob not available.\n");
2915 return;
2916 }
2917
2918 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2919
2920 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2921 ok(ret, "CreateProcessA error %u\n", GetLastError());
2922
2923 out = FALSE;
2924 ret = pIsProcessInJob(pi.hProcess, job, &out);
2925 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2926 ok(out, "IsProcessInJob returned out=%u\n", out);
2927 test_assigned_proc(job, 2, GetCurrentProcessId(), pi.dwProcessId);
2928 test_accounting(job, 2, 2, 0);
2929
2930 dwret = WaitForSingleObject(pi.hProcess, 1000);
2931 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2932
2933 CloseHandle(pi.hProcess);
2934 CloseHandle(pi.hThread);
2935 }
2936
2937 static void test_BreakawayOk(HANDLE job)
2938 {
2939 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2940 PROCESS_INFORMATION pi;
2941 STARTUPINFOA si = {0};
2942 char buffer[MAX_PATH];
2943 BOOL ret, out;
2944 DWORD dwret;
2945
2946 if (!pIsProcessInJob)
2947 {
2948 win_skip("IsProcessInJob not available.\n");
2949 return;
2950 }
2951
2952 sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2953
2954 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2955 ok(!ret, "CreateProcessA expected failure\n");
2956 expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2957 test_assigned_proc(job, 1, GetCurrentProcessId());
2958 test_accounting(job, 2, 1, 0);
2959
2960 if (ret)
2961 {
2962 TerminateProcess(pi.hProcess, 0);
2963
2964 dwret = WaitForSingleObject(pi.hProcess, 1000);
2965 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2966
2967 CloseHandle(pi.hProcess);
2968 CloseHandle(pi.hThread);
2969 }
2970
2971 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
2972 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2973 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2974
2975 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2976 ok(ret, "CreateProcessA error %u\n", GetLastError());
2977
2978 ret = pIsProcessInJob(pi.hProcess, job, &out);
2979 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2980 ok(!out, "IsProcessInJob returned out=%u\n", out);
2981 test_assigned_proc(job, 1, GetCurrentProcessId());
2982 test_accounting(job, 2, 1, 0);
2983
2984 dwret = WaitForSingleObject(pi.hProcess, 1000);
2985 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2986
2987 CloseHandle(pi.hProcess);
2988 CloseHandle(pi.hThread);
2989
2990 limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
2991 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2992 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2993
2994 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2995 ok(ret, "CreateProcess error %u\n", GetLastError());
2996
2997 ret = pIsProcessInJob(pi.hProcess, job, &out);
2998 ok(ret, "IsProcessInJob error %u\n", GetLastError());
2999 ok(!out, "IsProcessInJob returned out=%u\n", out);
3000 test_assigned_proc(job, 1, GetCurrentProcessId());
3001 test_accounting(job, 2, 1, 0);
3002
3003 dwret = WaitForSingleObject(pi.hProcess, 1000);
3004 ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
3005
3006 CloseHandle(pi.hProcess);
3007 CloseHandle(pi.hThread);
3008
3009 /* unset breakaway ok */
3010 limit_info.BasicLimitInformation.LimitFlags = 0;
3011 ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3012 ok(ret, "SetInformationJobObject error %u\n", GetLastError());
3013 }
3014
3015 static void test_StartupNoConsole(void)
3016 {
3017 #ifndef _WIN64
3018 char buffer[MAX_PATH];
3019 STARTUPINFOA startup;
3020 PROCESS_INFORMATION info;
3021
3022 memset(&startup, 0, sizeof(startup));
3023 startup.cb = sizeof(startup);
3024 startup.dwFlags = STARTF_USESHOWWINDOW;
3025 startup.wShowWindow = SW_SHOWNORMAL;
3026 get_file_name(resfile);
3027 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3028 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3029 &info), "CreateProcess\n");
3030 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3031 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3032 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3033 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3034 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3035 okChildInt("TEB", "hStdInput", 0);
3036 okChildInt("TEB", "hStdOutput", 0);
3037 okChildInt("TEB", "hStdError", 0);
3038 release_memory();
3039 DeleteFileA(resfile);
3040 #endif
3041 }
3042
3043 static void test_DetachConsoleHandles(void)
3044 {
3045 #ifndef _WIN64
3046 char buffer[MAX_PATH];
3047 STARTUPINFOA startup;
3048 PROCESS_INFORMATION info;
3049 UINT result;
3050
3051 memset(&startup, 0, sizeof(startup));
3052 startup.cb = sizeof(startup);
3053 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
3054 startup.wShowWindow = SW_SHOWNORMAL;
3055 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
3056 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
3057 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
3058 get_file_name(resfile);
3059 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3060 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3061 &info), "CreateProcess\n");
3062 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3063 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3064
3065 result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile);
3066 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3067 result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile);
3068 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3069 result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile);
3070 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3071 result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile);
3072 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3073 result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile);
3074 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3075 result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile);
3076 ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3077
3078 release_memory();
3079 DeleteFileA(resfile);
3080 #endif
3081 }
3082
3083 #if defined(__i386__) || defined(__x86_64__)
3084 static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi,
3085 IMAGE_NT_HEADERS *nt_header)
3086 {
3087 IMAGE_DOS_HEADER dos_header;
3088
3089 if (!ReadProcessMemory(process_handle, mbi->BaseAddress, &dos_header, sizeof(dos_header), NULL))
3090 return FALSE;
3091
3092 if ((dos_header.e_magic != IMAGE_DOS_SIGNATURE) ||
3093 ((ULONG)dos_header.e_lfanew > mbi->RegionSize) ||
3094 (dos_header.e_lfanew < sizeof(dos_header)))
3095 return FALSE;
3096
3097 if (!ReadProcessMemory(process_handle, (char *)mbi->BaseAddress + dos_header.e_lfanew,
3098 nt_header, sizeof(*nt_header), NULL))
3099 return FALSE;
3100
3101 return (nt_header->Signature == IMAGE_NT_SIGNATURE);
3102 }
3103
3104 static PVOID get_process_exe(HANDLE process_handle, IMAGE_NT_HEADERS *nt_header)
3105 {
3106 PVOID exe_base, address;
3107 MEMORY_BASIC_INFORMATION mbi;
3108
3109 /* Find the EXE base in the new process */
3110 exe_base = NULL;
3111 for (address = NULL ;
3112 VirtualQueryEx(process_handle, address, &mbi, sizeof(mbi)) ;
3113 address = (char *)mbi.BaseAddress + mbi.RegionSize) {
3114 if ((mbi.Type == SEC_IMAGE) &&
3115 read_nt_header(process_handle, &mbi, nt_header) &&
3116 !(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
3117 exe_base = mbi.BaseAddress;
3118 break;
3119 }
3120 }
3121
3122 return exe_base;
3123 }
3124
3125 static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE_NT_HEADERS *nt_header)
3126 {
3127 BOOL ret;
3128 IMAGE_IMPORT_DESCRIPTOR iid;
3129 ULONG_PTR orig_iat_entry_value, iat_entry_value;
3130
3131 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, "Import table VA is zero\n");
3132 ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, "Import table Size is zero\n");
3133
3134 if (!nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ||
3135 !nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
3136 return FALSE;
3137
3138 /* Read the first IID */
3139 ret = ReadProcessMemory(process_handle,
3140 (char *)module_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
3141 &iid, sizeof(iid), NULL);
3142 ok(ret, "Failed to read remote module IID (%d)\n", GetLastError());
3143
3144 /* Validate the IID is present and not a bound import, and that we have
3145 an OriginalFirstThunk to compare with */
3146 ok(iid.Name, "Module first IID does not have a Name\n");
3147 ok(iid.FirstThunk, "Module first IID does not have a FirstThunk\n");
3148 ok(!iid.TimeDateStamp, "Module first IID is a bound import (UNSUPPORTED for current test)\n");
3149 ok(iid.OriginalFirstThunk, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3150
3151 /* Read a single IAT entry from the FirstThunk */
3152 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.FirstThunk,
3153 &iat_entry_value, sizeof(iat_entry_value), NULL);
3154 ok(ret, "Failed to read IAT entry from FirstThunk (%d)\n", GetLastError());
3155 ok(iat_entry_value, "IAT entry in FirstThunk is NULL\n");
3156
3157 /* Read a single IAT entry from the OriginalFirstThunk */
3158 ret = ReadProcessMemory(process_handle, (char *)module_base + iid.OriginalFirstThunk,
3159 &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL);
3160 ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%d)\n", GetLastError());
3161 ok(orig_iat_entry_value, "IAT entry in OriginalFirstThunk is NULL\n");
3162
3163 return iat_entry_value != orig_iat_entry_value;
3164 }
3165
3166 static void test_SuspendProcessNewThread(void)
3167 {
3168 BOOL ret;
3169 STARTUPINFOA si = {0};
3170 PROCESS_INFORMATION pi = {0};
3171 PVOID exe_base, exit_thread_ptr;
3172 IMAGE_NT_HEADERS nt_header;
3173 HANDLE thread_handle = NULL;
3174 DWORD dret, exit_code = 0;
3175 CONTEXT ctx;
3176
3177 exit_thread_ptr = GetProcAddress(hkernel32, "ExitThread");
3178 ok(exit_thread_ptr != NULL, "GetProcAddress ExitThread failed\n");
3179
3180 si.cb = sizeof(si);
3181 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3182 ok(ret, "Failed to create process (%d)\n", GetLastError());
3183
3184 exe_base = get_process_exe(pi.hProcess, &nt_header);
3185 ok(exe_base != NULL, "Could not find EXE in remote process\n");
3186
3187 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3188 ok(!ret, "IAT entry resolved prematurely\n");
3189
3190 thread_handle = CreateRemoteThread(pi.hProcess, NULL, 0,
3191 (LPTHREAD_START_ROUTINE)exit_thread_ptr,
3192 (PVOID)(ULONG_PTR)0x1234, CREATE_SUSPENDED, NULL);
3193 ok(thread_handle != NULL, "Could not create remote thread (%d)\n", GetLastError());
3194
3195 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3196 ok(!ret, "IAT entry resolved prematurely\n");
3197
3198 ctx.ContextFlags = CONTEXT_ALL;
3199 ret = GetThreadContext( thread_handle, &ctx );
3200 ok( ret, "Failed retrieving remote thread context (%d)\n", GetLastError() );
3201 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags );
3202 #ifdef __x86_64__
3203 ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax );
3204 ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx );
3205 ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %lx/%p\n", ctx.Rcx, exit_thread_ptr );
3206 ok( ctx.Rdx == 0x1234, "wrong rdx %lx\n", ctx.Rdx );
3207 ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi );
3208 ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi );
3209 ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp );
3210 ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 );
3211 ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 );
3212 ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 );
3213 ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 );
3214 ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 );
3215 ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 );
3216 ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 );
3217 ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 );
3218 ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp );
3219 ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags );
3220 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr );
3221 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3222 #else
3223 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp );
3224 if (!ctx.Ebp) /* winxp is completely different */
3225 {
3226 ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx );
3227 ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx );
3228 ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi );
3229 ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi );
3230 }
3231 ok( ctx.Eax == (ULONG_PTR)exit_thread_ptr, "wrong eax %08x/%p\n", ctx.Eax, exit_thread_ptr );
3232 ok( ctx.Ebx == 0x1234, "wrong ebx %08x\n", ctx.Ebx );
3233 ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3234 "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp );
3235 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags );
3236 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord );
3237 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3238 #endif
3239
3240 ResumeThread( thread_handle );
3241 dret = WaitForSingleObject(thread_handle, 60000);
3242 ok(dret == WAIT_OBJECT_0, "Waiting for remote thread failed (%d)\n", GetLastError());
3243 ret = GetExitCodeThread(thread_handle, &exit_code);
3244 ok(ret, "Failed to retrieve remote thread exit code (%d)\n", GetLastError());
3245 ok(exit_code == 0x1234, "Invalid remote thread exit code\n");
3246
3247 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3248 ok(ret, "EXE IAT entry not resolved\n");
3249
3250 if (thread_handle)
3251 CloseHandle(thread_handle);
3252
3253 TerminateProcess(pi.hProcess, 0);
3254 WaitForSingleObject(pi.hProcess, 10000);
3255 CloseHandle(pi.hProcess);
3256 CloseHandle(pi.hThread);
3257 }
3258
3259 static void test_SuspendProcessState(void)
3260 {
3261 struct pipe_params
3262 {
3263 ULONG pipe_write_buf;
3264 ULONG pipe_read_buf;
3265 ULONG bytes_returned;
3266 CHAR pipe_name[MAX_PATH];
3267 };
3268
3269 #ifdef __x86_64__
3270 struct remote_rop_chain
3271 {
3272 void *exit_process_ptr;
3273 ULONG_PTR home_rcx;
3274 ULONG_PTR home_rdx;
3275 ULONG_PTR home_r8;
3276 ULONG_PTR home_r9;
3277 ULONG_PTR pipe_read_buf_size;
3278 ULONG_PTR bytes_returned;
3279 ULONG_PTR timeout;
3280 };
3281 #else
3282 struct remote_rop_chain
3283 {
3284 void *exit_process_ptr;
3285 ULONG_PTR pipe_name;
3286 ULONG_PTR pipe_write_buf;
3287 ULONG_PTR pipe_write_buf_size;
3288 ULONG_PTR pipe_read_buf;
3289 ULONG_PTR pipe_read_buf_size;
3290 ULONG_PTR bytes_returned;
3291 ULONG_PTR timeout;
3292 void *unreached_ret;
3293 ULONG_PTR exit_code;
3294 };
3295 #endif
3296
3297 static const char pipe_name[] = "\\\\.\\pipe\\TestPipe";
3298 static const ULONG pipe_write_magic = 0x454e4957;
3299 STARTUPINFOA si = {0};
3300 PROCESS_INFORMATION pi = {0};
3301 PVOID exe_base, remote_pipe_params, exit_process_ptr,
3302 call_named_pipe_a;
3303 IMAGE_NT_HEADERS nt_header;
3304 struct pipe_params pipe_params;
3305 struct remote_rop_chain rop_chain;
3306 CONTEXT ctx;
3307 HANDLE server_pipe_handle;
3308 BOOL pipe_connected;
3309 ULONG pipe_magic, numb;
3310 BOOL ret;
3311 void *entry_ptr, *peb_ptr;
3312 PEB child_peb;
3313
3314 exit_process_ptr = GetProcAddress(hkernel32, "ExitProcess");
3315 ok(exit_process_ptr != NULL, "GetProcAddress ExitProcess failed\n");
3316
3317 call_named_pipe_a = GetProcAddress(hkernel32, "CallNamedPipeA");
3318 ok(call_named_pipe_a != NULL, "GetProcAddress CallNamedPipeA failed\n");
3319
3320 si.cb = sizeof(si);
3321 ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3322 ok(ret, "Failed to create process (%d)\n", GetLastError());
3323
3324 exe_base = get_process_exe(pi.hProcess, &nt_header);
3325 /* Make sure we found the EXE in the new process */
3326 ok(exe_base != NULL, "Could not find EXE in remote process\n");
3327
3328 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3329 ok(!ret, "IAT entry resolved prematurely\n");
3330
3331 server_pipe_handle = CreateNamedPipeA(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH,
3332 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0x20000, 0x20000,
3333 0, NULL);
3334 ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%d)\n", GetLastError());
3335
3336 /* Set up the remote process environment */
3337 ctx.ContextFlags = CONTEXT_ALL;
3338 ret = GetThreadContext(pi.hThread, &ctx);
3339 ok(ret, "Failed retrieving remote thread context (%d)\n", GetLastError());
3340 ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags );
3341
3342 remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE);
3343 ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%d)\n", GetLastError());
3344
3345 pipe_params.pipe_write_buf = pipe_write_magic;
3346 pipe_params.pipe_read_buf = 0;
3347 pipe_params.bytes_returned = 0;
3348 strcpy(pipe_params.pipe_name, pipe_name);
3349
3350 ret = WriteProcessMemory(pi.hProcess, remote_pipe_params,
3351 &pipe_params, sizeof(pipe_params), NULL);
3352 ok(ret, "Failed to write to remote process memory (%d)\n", GetLastError());
3353
3354 #ifdef __x86_64__
3355 ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax );
3356 ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx );
3357 ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi );
3358 ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi );
3359 ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp );
3360 ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 );
3361 ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 );
3362 ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 );
3363 ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 );
3364 ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 );
3365 ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 );
3366 ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 );
3367 ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 );
3368 ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp );
3369 ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags );
3370 ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr );
3371 ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3372 entry_ptr = (void *)ctx.Rcx;
3373 peb_ptr = (void *)ctx.Rdx;
3374
3375 rop_chain.exit_process_ptr = exit_process_ptr;
3376 ctx.Rcx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3377 ctx.Rdx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3378 ctx.R8 = sizeof(pipe_params.pipe_write_buf);
3379 ctx.R9 = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3380 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3381 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3382 rop_chain.timeout = 10000;
3383
3384 ctx.Rip = (ULONG_PTR)call_named_pipe_a;
3385 ctx.Rsp -= sizeof(rop_chain);
3386 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL);
3387 ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3388 #else
3389 ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp );
3390 if (!ctx.Ebp) /* winxp is completely different */
3391 {
3392 ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx );
3393 ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx );
3394 ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi );
3395 ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi );
3396 }
3397 ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3398 "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp );
3399 ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags );
3400 ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord );
3401 ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3402 entry_ptr = (void *)ctx.Eax;
3403 peb_ptr = (void *)ctx.Ebx;
3404
3405 rop_chain.exit_process_ptr = exit_process_ptr;
3406 rop_chain.pipe_name = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3407 rop_chain.pipe_write_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3408 rop_chain.pipe_write_buf_size = sizeof(pipe_params.pipe_write_buf);
3409 rop_chain.pipe_read_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3410 rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3411 rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3412 rop_chain.timeout = 10000;
3413 rop_chain.exit_code = 0;
3414
3415 ctx.Eip = (ULONG_PTR)call_named_pipe_a;
3416 ctx.Esp -= sizeof(rop_chain);
3417 ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Esp, &rop_chain, sizeof(rop_chain), NULL);
3418 ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3419 #endif
3420
3421 ret = ReadProcessMemory( pi.hProcess, peb_ptr, &child_peb, sizeof(child_peb), NULL );
3422 ok( ret, "Failed to read PEB (%u)\n", GetLastError() );
3423 ok( child_peb.ImageBaseAddress == exe_base, "wrong base %p/%p\n",
3424 child_peb.ImageBaseAddress, exe_base );
3425 ok( entry_ptr == (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint,
3426 "wrong entry point %p/%p\n", entry_ptr,
3427 (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint );
3428
3429 ret = SetThreadContext(pi.hThread, &ctx);
3430 ok(ret, "Failed to set remote thread context (%d)\n", GetLastError());
3431
3432 ResumeThread(pi.hThread);
3433
3434 pipe_connected = ConnectNamedPipe(server_pipe_handle, NULL) || (GetLastError() == ERROR_PIPE_CONNECTED);
3435 ok(pipe_connected, "Pipe did not connect\n");
3436
3437 ret = ReadFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3438 ok(ret, "Failed to read buffer from pipe (%d)\n", GetLastError());
3439
3440 ok(pipe_magic == pipe_write_magic, "Did not get the correct magic from the remote process\n");
3441
3442 /* Validate the Imports, at this point the thread in the new process should have
3443 initialized the EXE module imports and call each dll DllMain notifying it on
3444 the new thread in the process. */
3445 ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3446 ok(ret, "EXE IAT is not resolved\n");
3447
3448 ret = WriteFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3449 ok(ret, "Failed to write the magic back to the pipe (%d)\n", GetLastError());
3450
3451 CloseHandle(server_pipe_handle);
3452 TerminateProcess(pi.hProcess, 0);
3453 WaitForSingleObject(pi.hProcess, 10000);
3454 CloseHandle(pi.hProcess);
3455 CloseHandle(pi.hThread);
3456 }
3457 #else
3458 static void test_SuspendProcessNewThread(void)
3459 {
3460 }
3461 static void test_SuspendProcessState(void)
3462 {
3463 }
3464 #endif
3465
3466 static void test_DetachStdHandles(void)
3467 {
3468 #ifndef _WIN64
3469 char buffer[MAX_PATH], tempfile[MAX_PATH];
3470 STARTUPINFOA startup;
3471 PROCESS_INFORMATION info;
3472 HANDLE hstdin, hstdout, hstderr, htemp;
3473 BOOL res;
3474
3475 hstdin = GetStdHandle(STD_INPUT_HANDLE);
3476 hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
3477 hstderr = GetStdHandle(STD_ERROR_HANDLE);
3478
3479 get_file_name(tempfile);
3480 htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3481 ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n");
3482
3483 memset(&startup, 0, sizeof(startup));
3484 startup.cb = sizeof(startup);
3485 startup.dwFlags = STARTF_USESHOWWINDOW;
3486 startup.wShowWindow = SW_SHOWNORMAL;
3487 get_file_name(resfile);
3488 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3489
3490 SetStdHandle(STD_INPUT_HANDLE, htemp);
3491 SetStdHandle(STD_OUTPUT_HANDLE, htemp);
3492 SetStdHandle(STD_ERROR_HANDLE, htemp);
3493
3494 res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3495 &info);
3496
3497 SetStdHandle(STD_INPUT_HANDLE, hstdin);
3498 SetStdHandle(STD_OUTPUT_HANDLE, hstdout);
3499 SetStdHandle(STD_ERROR_HANDLE, hstderr);
3500
3501 ok(res, "CreateProcess failed\n");
3502 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3503 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3504 okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3505 okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3506 okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3507 okChildInt("TEB", "hStdInput", 0);
3508 okChildInt("TEB", "hStdOutput", 0);
3509 okChildInt("TEB", "hStdError", 0);
3510 release_memory();
3511 DeleteFileA(resfile);
3512
3513 CloseHandle(htemp);
3514 DeleteFileA(tempfile);
3515 #endif
3516 }
3517
3518 static void test_GetNumaProcessorNode(void)
3519 {
3520 SYSTEM_INFO si;
3521 UCHAR node;
3522 BOOL ret;
3523 int i;
3524
3525 if (!pGetNumaProcessorNode)
3526 {
3527 win_skip("GetNumaProcessorNode is missing\n");
3528 return;
3529 }
3530
3531 GetSystemInfo(&si);
3532 for (i = 0; i < 256; i++)
3533 {
3534 SetLastError(0xdeadbeef);
3535 node = (i < si.dwNumberOfProcessors) ? 0xFF : 0xAA;
3536 ret = pGetNumaProcessorNode(i, &node);
3537 if (i < si.dwNumberOfProcessors)
3538 {
3539 ok(ret, "GetNumaProcessorNode returned FALSE for processor %d\n", i);
3540 ok(node != 0xFF, "expected node != 0xFF, but got 0xFF\n");
3541 }
3542 else
3543 {
3544 ok(!ret, "GetNumaProcessorNode returned TRUE for processor %d\n", i);
3545 ok(node == 0xFF || broken(node == 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node);
3546 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3547 }
3548 }
3549 }
3550
3551 static void test_session_info(void)
3552 {
3553 DWORD session_id, active_session;
3554 BOOL r;
3555
3556 if (!pProcessIdToSessionId)
3557 {
3558 win_skip("ProcessIdToSessionId is missing\n");
3559 return;
3560 }
3561
3562 r = pProcessIdToSessionId(GetCurrentProcessId(), &session_id);
3563 ok(r, "ProcessIdToSessionId failed: %u\n", GetLastError());
3564 trace("session_id = %x\n", session_id);
3565
3566 active_session = pWTSGetActiveConsoleSessionId();
3567 trace("active_session = %x\n", active_session);
3568 }
3569
3570 static void test_process_info(void)
3571 {
3572 char buf[4096];
3573 static const ULONG info_size[] =
3574 {
3575 sizeof(PROCESS_BASIC_INFORMATION) /* ProcessBasicInformation */,
3576 sizeof(QUOTA_LIMITS) /* ProcessQuotaLimits */,
3577 sizeof(IO_COUNTERS) /* ProcessIoCounters */,
3578 sizeof(VM_COUNTERS) /* ProcessVmCounters */,
3579 sizeof(KERNEL_USER_TIMES) /* ProcessTimes */,
3580 sizeof(ULONG) /* ProcessBasePriority */,
3581 sizeof(ULONG) /* ProcessRaisePriority */,
3582 sizeof(HANDLE) /* ProcessDebugPort */,
3583 sizeof(HANDLE) /* ProcessExceptionPort */,
3584 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3585 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3586 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3587 sizeof(ULONG) /* ProcessDefaultHardErrorMode */,
3588 0 /* ProcessIoPortHandlers: kernel-mode only */,
3589 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3590 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3591 sizeof(ULONG) /* ProcessUserModeIOPL */,
3592 sizeof(BOOLEAN) /* ProcessEnableAlignmentFaultFixup */,
3593 sizeof(PROCESS_PRIORITY_CLASS) /* ProcessPriorityClass */,
3594 sizeof(ULONG) /* ProcessWx86Information */,
3595 sizeof(ULONG) /* ProcessHandleCount */,
3596 sizeof(ULONG_PTR) /* ProcessAffinityMask */,
3597 sizeof(ULONG) /* ProcessPriorityBoost */,
3598 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3599 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3600 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3601 sizeof(ULONG_PTR) /* ProcessWow64Information */,
3602 sizeof(buf) /* ProcessImageFileName */,
3603 sizeof(ULONG) /* ProcessLUIDDeviceMapsEnabled */,
3604 sizeof(ULONG) /* ProcessBreakOnTermination */,
3605 sizeof(HANDLE) /* ProcessDebugObjectHandle */,
3606 sizeof(ULONG) /* ProcessDebugFlags */,
3607 sizeof(buf) /* ProcessHandleTracing */,
3608 sizeof(ULONG) /* ProcessIoPriority */,
3609 sizeof(ULONG) /* ProcessExecuteFlags */,
3610 0 /* FIXME: sizeof(?) ProcessTlsInformation */,
3611 0 /* FIXME: sizeof(?) ProcessCookie */,
3612 sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */,
3613 0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */,
3614 sizeof(ULONG) /* ProcessPagePriority */,
3615 40 /* ProcessInstrumentationCallback */,
3616 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
3617 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
3618 sizeof(buf) /* ProcessImageFileNameWin32 */,
3619 sizeof(HANDLE) /* ProcessImageFileMapping */,
3620 0 /* FIXME: sizeof(PROCESS_AFFINITY_UPDATE_MODE) ProcessAffinityUpdateMode */,
3621 0 /* FIXME: sizeof(PROCESS_MEMORY_ALLOCATION_MODE) ProcessMemoryAllocationMode */,
3622 sizeof(USHORT) /* ProcessGroupInformation */,
3623 sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */,
3624 sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */,
3625 0 /* FIXME: sizeof(PROCESS_WINDOW_INFORMATION) ProcessWindowInformation */,
3626 #if 0 /* FIXME: Add remaining classes */
3627 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */,
3628 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */,
3629 sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */,
3630 sizeof(?) /* ProcessHandleCheckingMode */,
3631 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION) /* ProcessKeepAliveCount */,
3632 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION) /* ProcessRevokeFileHandles */,
3633 sizeof(PROCESS_WORKING_SET_CONTROL) /* ProcessWorkingSetControl */,
3634 sizeof(?) /* ProcessHandleTable */,
3635 sizeof(?) /* ProcessCheckStackExtentsMode */,
3636 sizeof(buf) /* ProcessCommandLineInformation */,
3637 sizeof(PS_PROTECTION) /* ProcessProtectionInformation */,
3638 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO) /* ProcessMemoryExhaustion */,
3639 sizeof(PROCESS_FAULT_INFORMATION) /* ProcessFaultInformation */,
3640 sizeof(PROCESS_TELEMETRY_ID_INFORMATION) /* ProcessTelemetryIdInformation */,
3641 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION) /* ProcessCommitReleaseInformation */,
3642 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3643 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3644 0 /* ProcessReserved1Information */,
3645 0 /* ProcessReserved2Information */,
3646 sizeof(?) /* ProcessSubsystemProcess */,
3647 sizeof(PROCESS_JOB_MEMORY_INFO) /* ProcessJobMemoryInformation */,
3648 #endif
3649 };
3650 HANDLE hproc;
3651 ULONG i, status, ret_len, size;
3652
3653 if (!pNtQueryInformationProcess)
3654 {
3655 win_skip("NtQueryInformationProcess is not available on this platform\n");
3656 return;
3657 }
3658
3659 hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
3660 if (!hproc)
3661 {
3662 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
3663 return;
3664 }
3665
3666 for (i = 0; i < MaxProcessInfoClass; i++)
3667 {
3668 size = info_size[i];
3669 if (!size) size = sizeof(buf);
3670 ret_len = 0;
3671 status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len);
3672 if (status == STATUS_NOT_IMPLEMENTED) continue;
3673 if (status == STATUS_INVALID_INFO_CLASS) continue;
3674 if (status == STATUS_INFO_LENGTH_MISMATCH) continue;
3675
3676 switch (i)
3677 {
3678 case ProcessBasicInformation:
3679 case ProcessQuotaLimits:
3680 case ProcessTimes:
3681 case ProcessPriorityClass:
3682 case ProcessPriorityBoost:
3683 case ProcessLUIDDeviceMapsEnabled:
3684 case 33 /* ProcessIoPriority */:
3685 case ProcessIoCounters:
3686 case ProcessVmCounters:
3687 case ProcessWow64Information:
3688 case ProcessDefaultHardErrorMode:
3689 case ProcessHandleCount:
3690 case ProcessImageFileName:
3691 case ProcessImageInformation:
3692 case ProcessPagePriority:
3693 case ProcessImageFileNameWin32:
3694 ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3695 break;
3696
3697 case ProcessAffinityMask:
3698 case ProcessBreakOnTermination:
3699 case ProcessGroupInformation:
3700 case ProcessConsoleHostProcess:
3701 ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */,
3702 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3703 break;
3704
3705 case ProcessDebugObjectHandle:
3706 ok(status == STATUS_ACCESS_DENIED || status == STATUS_PORT_NOT_SET,
3707 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3708 break;
3709
3710 case ProcessExecuteFlags:
3711 case ProcessDebugPort:
3712 case ProcessDebugFlags:
3713 case ProcessCookie:
3714 todo_wine
3715 ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3716 break;
3717
3718 default:
3719 ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3720 break;
3721 }
3722 }
3723
3724 CloseHandle(hproc);
3725 }
3726
3727 static void test_GetLogicalProcessorInformationEx(void)
3728 {
3729 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info;
3730 DWORD len;
3731 BOOL ret;
3732
3733 if (!pGetLogicalProcessorInformationEx)
3734 {
3735 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3736 return;
3737 }
3738
3739 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, NULL);
3740 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
3741
3742 len = 0;
3743 ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len);
3744 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3745 ok(len > 0, "got %u\n", len);
3746
3747 len = 0;
3748 ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len);
3749 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3750 ok(len > 0, "got %u\n", len);
3751
3752 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
3753 ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len);
3754 ok(ret, "got %d, error %d\n", ret, GetLastError());
3755 ok(info->Size > 0, "got %u\n", info->Size);
3756 HeapFree(GetProcessHeap(), 0, info);
3757 }
3758
3759 static void test_largepages(void)
3760 {
3761 SIZE_T size;
3762
3763 if (!pGetLargePageMinimum) {
3764 skip("No GetLargePageMinimum support.\n");
3765 return;
3766 }
3767 size = pGetLargePageMinimum();
3768
3769 ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size);
3770 }
3771
3772 struct proc_thread_attr
3773 {
3774 DWORD_PTR attr;
3775 SIZE_T size;
3776 void *value;
3777 };
3778
3779 struct _PROC_THREAD_ATTRIBUTE_LIST
3780 {
3781 DWORD mask; /* bitmask of items in list */
3782 DWORD size; /* max number of items in list */
3783 DWORD count; /* number of items in list */
3784 DWORD pad;
3785 DWORD_PTR unk;
3786 struct proc_thread_attr attrs[10];
3787 };
3788
3789 static void test_ProcThreadAttributeList(void)
3790 {
3791 BOOL ret;
3792 SIZE_T size, needed;
3793 int i;
3794 struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list;
3795 HANDLE handles[4];
3796
3797 if (!pInitializeProcThreadAttributeList)
3798 {
3799 win_skip("No support for ProcThreadAttributeList\n");
3800 return;
3801 }
3802
3803 for (i = 0; i <= 10; i++)
3804 {
3805 needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[i]);
3806 ret = pInitializeProcThreadAttributeList(NULL, i, 0, &size);
3807 ok(!ret, "got %d\n", ret);
3808 if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */
3809 break;
3810 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
3811 ok(size == needed, "%d: got %ld expect %ld\n", i, size, needed);
3812
3813 memset(&list, 0xcc, sizeof(list));
3814 ret = pInitializeProcThreadAttributeList(&list, i, 0, &size);
3815 ok(ret, "got %d\n", ret);
3816 ok(list.mask == 0, "%d: got %08x\n", i, list.mask);
3817 ok(list.size == i, "%d: got %08x\n", i, list.size);
3818 ok(list.count == 0, "%d: got %08x\n", i, list.count);
3819 ok(list.unk == 0, "%d: got %08lx\n", i, list.unk);
3820 }
3821
3822 memset(handles, 0, sizeof(handles));
3823 memset(&expect_list, 0xcc, sizeof(expect_list));
3824 expect_list.mask = 0;
3825 expect_list.size = i - 1;
3826 expect_list.count = 0;
3827 expect_list.unk = 0;
3828
3829 ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3830 ok(!ret, "got %d\n", ret);
3831 ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %d\n", GetLastError());
3832
3833 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL);
3834 ok(!ret, "got %d\n", ret);
3835 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3836
3837 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL);
3838 ok(!ret, "got %d\n", ret);
3839 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3840
3841 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3842 ok(ret, "got %d\n", ret);
3843
3844 expect_list.mask |= 1 << ProcThreadAttributeParentProcess;
3845 expect_list.attrs[0].attr = PROC_THREAD_ATTRIBUTE_PARENT_PROCESS;
3846 expect_list.attrs[0].size = sizeof(handles[0]);
3847 expect_list.attrs[0].value = handles;
3848 expect_list.count++;
3849
3850 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3851 ok(!ret, "got %d\n", ret);
3852 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3853
3854 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL);
3855 ok(!ret, "got %d\n", ret);
3856 ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3857
3858 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3859 ok(ret, "got %d\n", ret);
3860
3861 expect_list.mask |= 1 << ProcThreadAttributeHandleList;
3862 expect_list.attrs[1].attr = PROC_THREAD_ATTRIBUTE_HANDLE_LIST;
3863 expect_list.attrs[1].size = sizeof(handles);
3864 expect_list.attrs[1].value = handles;
3865 expect_list.count++;
3866
3867 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3868 ok(!ret, "got %d\n", ret);
3869 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3870
3871 ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3872 ok(ret || GetLastError() == ERROR_NOT_SUPPORTED, "got %d gle %d\n", ret, GetLastError());
3873
3874 if (ret)
3875 {
3876 expect_list.mask |= 1 << ProcThreadAttributeIdealProcessor;
3877 expect_list.attrs[2].attr = PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR;
3878 expect_list.attrs[2].size = sizeof(PROCESSOR_NUMBER);
3879 expect_list.attrs[2].value = handles;
3880 expect_list.count++;
3881 }
3882
3883 ok(!memcmp(&list, &expect_list, size), "mismatch\n");
3884
3885 pDeleteProcThreadAttributeList(&list);
3886 }
3887
3888 static void test_GetActiveProcessorCount(void)
3889 {
3890 DWORD count;
3891
3892 if (!pGetActiveProcessorCount)
3893 {
3894 win_skip("GetActiveProcessorCount not available, skipping test\n");
3895 return;
3896 }
3897
3898 count = pGetActiveProcessorCount(0);
3899 ok(count, "GetActiveProcessorCount failed, error %u\n", GetLastError());
3900
3901 /* Test would fail on systems with more than 6400 processors */
3902 SetLastError(0xdeadbeef);
3903 count = pGetActiveProcessorCount(101);
3904 ok(count == 0, "Expeced GetActiveProcessorCount to fail\n");
3905 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3906 }
3907
3908 START_TEST(process)
3909 {
3910 HANDLE job;
3911 BOOL b = init();
3912 ok(b, "Basic init of CreateProcess test\n");
3913 if (!b) return;
3914
3915 if (myARGC >= 3)
3916 {
3917 if (!strcmp(myARGV[2], "dump") && myARGC >= 4)
3918 {
3919 doChild(myARGV[3], (myARGC >= 5) ? myARGV[4] : NULL);
3920 return;
3921 }
3922 else if (!strcmp(myARGV[2], "wait"))
3923 {
3924 Sleep(30000);
3925 ok(0, "Child process not killed\n");
3926 return;
3927 }
3928 else if (!strcmp(myARGV[2], "exit"))
3929 {
3930 Sleep(100);
3931 return;
3932 }
3933 else if (!strcmp(myARGV[2], "nested") && myARGC >= 4)
3934 {
3935 char buffer[MAX_PATH];
3936 STARTUPINFOA startup;
3937 PROCESS_INFORMATION info;
3938
3939 memset(&startup, 0, sizeof(startup));
3940 startup.cb = sizeof(startup);
3941 startup.dwFlags = STARTF_USESHOWWINDOW;
3942 startup.wShowWindow = SW_SHOWNORMAL;
3943
3944 sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, myARGV[3]);
3945 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n");
3946 CloseHandle(info.hProcess);
3947 CloseHandle(info.hThread);
3948 return;
3949 }
3950
3951 ok(0, "Unexpected command %s\n", myARGV[2]);
3952 return;
3953 }
3954
3955 test_process_info();
3956 test_TerminateProcess();
3957 test_Startup();
3958 test_CommandLine();
3959 test_Directory();
3960 test_Toolhelp();
3961 test_Environment();
3962 test_SuspendFlag();
3963 test_DebuggingFlag();
3964 test_Console();
3965 test_ExitCode();
3966 test_OpenProcess();
3967 test_GetProcessVersion();
3968 test_GetProcessImageFileNameA();
3969 test_QueryFullProcessImageNameA();
3970 test_QueryFullProcessImageNameW();
3971 test_Handles();
3972 test_IsWow64Process();
3973 test_SystemInfo();
3974 test_RegistryQuota();
3975 test_DuplicateHandle();
3976 test_StartupNoConsole();
3977 test_DetachConsoleHandles();
3978 test_DetachStdHandles();
3979 test_GetNumaProcessorNode();
3980 test_session_info();
3981 test_GetLogicalProcessorInformationEx();
3982 test_GetActiveProcessorCount();
3983 test_largepages();
3984 test_ProcThreadAttributeList();
3985 test_SuspendProcessState();
3986 test_SuspendProcessNewThread();
3987
3988 /* things that can be tested:
3989 * lookup: check the way program to be executed is searched
3990 * handles: check the handle inheritance stuff (+sec options)
3991 * console: check if console creation parameters work
3992 */
3993
3994 if (!pCreateJobObjectW)
3995 {
3996 win_skip("No job object support\n");
3997 return;
3998 }
3999
4000 test_IsProcessInJob();
4001 test_TerminateJobObject();
4002 test_QueryInformationJobObject();
4003 test_CompletionPort();
4004 test_KillOnJobClose();
4005 test_WaitForJobObject();
4006 job = test_AddSelfToJob();
4007 test_jobInheritance(job);
4008 test_BreakawayOk(job);
4009 CloseHandle(job);
4010 }