2 * Unit test suite for process functions
4 * Copyright 2002 Eric Pouech
5 * Copyright 2006 Dmitry Timoshkov
6 * Copyright 2014 Michael Müller
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #define WIN32_NO_STATUS
38 #include "wine/test.h"
39 #include "wine/heap.h"
41 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
42 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
43 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
44 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
46 #define expect_eq_d(expected, actual) \
48 int value = (actual); \
49 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
50 (int)(expected), value); \
52 #define expect_eq_s(expected, actual) \
54 LPCSTR value = (actual); \
55 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
58 #define expect_eq_ws_i(expected, actual) \
60 LPCWSTR value = (actual); \
61 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
62 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
65 static HINSTANCE hkernel32
, hntdll
;
66 static void (WINAPI
*pGetNativeSystemInfo
)(LPSYSTEM_INFO
);
67 static BOOL (WINAPI
*pGetSystemRegistryQuota
)(PDWORD
, PDWORD
);
68 static BOOL (WINAPI
*pIsWow64Process
)(HANDLE
,PBOOL
);
69 static BOOL (WINAPI
*pIsWow64Process2
)(HANDLE
, USHORT
*, USHORT
*);
70 static BOOL (WINAPI
*pQueryFullProcessImageNameA
)(HANDLE hProcess
, DWORD dwFlags
, LPSTR lpExeName
, PDWORD lpdwSize
);
71 static BOOL (WINAPI
*pQueryFullProcessImageNameW
)(HANDLE hProcess
, DWORD dwFlags
, LPWSTR lpExeName
, PDWORD lpdwSize
);
72 static DWORD (WINAPI
*pK32GetProcessImageFileNameA
)(HANDLE
,LPSTR
,DWORD
);
73 static HANDLE (WINAPI
*pCreateJobObjectW
)(LPSECURITY_ATTRIBUTES sa
, LPCWSTR name
);
74 static HANDLE (WINAPI
*pOpenJobObjectA
)(DWORD access
, BOOL inherit
, LPCSTR name
);
75 static BOOL (WINAPI
*pAssignProcessToJobObject
)(HANDLE job
, HANDLE process
);
76 static BOOL (WINAPI
*pIsProcessInJob
)(HANDLE process
, HANDLE job
, PBOOL result
);
77 static BOOL (WINAPI
*pTerminateJobObject
)(HANDLE job
, UINT exit_code
);
78 static BOOL (WINAPI
*pQueryInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
, LPDWORD ret_len
);
79 static BOOL (WINAPI
*pSetInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
);
80 static HANDLE (WINAPI
*pCreateIoCompletionPort
)(HANDLE file
, HANDLE existing_port
, ULONG_PTR key
, DWORD threads
);
81 static BOOL (WINAPI
*pGetNumaProcessorNode
)(UCHAR
, PUCHAR
);
82 static NTSTATUS (WINAPI
*pNtQueryInformationProcess
)(HANDLE
, PROCESSINFOCLASS
, PVOID
, ULONG
, PULONG
);
83 static NTSTATUS (WINAPI
*pNtQueryInformationThread
)(HANDLE
, THREADINFOCLASS
, PVOID
, ULONG
, PULONG
);
84 static NTSTATUS (WINAPI
*pNtQuerySystemInformationEx
)(SYSTEM_INFORMATION_CLASS
, void*, ULONG
, void*, ULONG
, ULONG
*);
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
*pGetSystemCpuSetInformation
)(SYSTEM_CPU_SET_INFORMATION
*,ULONG
,ULONG
*,HANDLE
,ULONG
);
94 static BOOL (WINAPI
*pInitializeProcThreadAttributeList
)(struct _PROC_THREAD_ATTRIBUTE_LIST
*, DWORD
, DWORD
, SIZE_T
*);
95 static BOOL (WINAPI
*pUpdateProcThreadAttribute
)(struct _PROC_THREAD_ATTRIBUTE_LIST
*, DWORD
, DWORD_PTR
, void *,SIZE_T
,void*,SIZE_T
*);
96 static void (WINAPI
*pDeleteProcThreadAttributeList
)(struct _PROC_THREAD_ATTRIBUTE_LIST
*);
97 static DWORD (WINAPI
*pGetActiveProcessorCount
)(WORD
);
98 static DWORD (WINAPI
*pGetMaximumProcessorCount
)(WORD
);
100 /* ############################### */
101 static char base
[MAX_PATH
];
102 static char selfname
[MAX_PATH
];
103 static char* exename
;
104 static char resfile
[MAX_PATH
];
107 static char** myARGV
;
109 /* As some environment variables get very long on Unix, we only test for
110 * the first 127 bytes.
111 * Note that increasing this value past 256 may exceed the buffer size
112 * limitations of the *Profile functions (at least on Wine).
114 #define MAX_LISTED_ENV_VAR 128
116 /* ---------------- portable memory allocation thingie */
118 static char memory
[1024*256];
119 static char* memory_index
= memory
;
121 static char* grab_memory(size_t len
)
123 char* ret
= memory_index
;
125 len
= (len
+ 3) & ~3;
127 assert(memory_index
<= memory
+ sizeof(memory
));
131 static void release_memory(void)
133 memory_index
= memory
;
136 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
138 static const char* encodeA(const char* str
)
144 len
= strlen(str
) + 1;
145 ptr
= grab_memory(len
* 2 + 1);
146 for (i
= 0; i
< len
; i
++)
147 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
152 static const char* encodeW(const WCHAR
* str
)
158 len
= lstrlenW(str
) + 1;
159 ptr
= grab_memory(len
* 4 + 1);
161 for (i
= 0; i
< len
; i
++)
162 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
167 static unsigned decode_char(char c
)
169 if (c
>= '0' && c
<= '9') return c
- '0';
170 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
171 assert(c
>= 'A' && c
<= 'F');
175 static char* decodeA(const char* str
)
180 len
= strlen(str
) / 2;
181 if (!len
--) return NULL
;
182 ptr
= grab_memory(len
+ 1);
183 for (i
= 0; i
< len
; i
++)
184 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
189 /* This will be needed to decode Unicode strings saved by the child process
190 * when we test Unicode functions.
192 static WCHAR
* decodeW(const char* str
)
198 len
= strlen(str
) / 4;
199 if (!len
--) return NULL
;
200 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
201 for (i
= 0; i
< len
; i
++)
202 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
203 (decode_char(str
[4 * i
+ 1]) << 8) |
204 (decode_char(str
[4 * i
+ 2]) << 4) |
205 (decode_char(str
[4 * i
+ 3]) << 0);
210 static void wait_and_close_child_process(PROCESS_INFORMATION
*pi
)
212 wait_child_process(pi
->hProcess
);
213 CloseHandle(pi
->hThread
);
214 CloseHandle(pi
->hProcess
);
217 static void reload_child_info(const char* resfile
)
219 /* This forces the profile functions to reload the resource file
220 * after the child process has modified it.
222 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
225 /******************************************************************
228 * generates basic information like:
229 * base: absolute path to curr dir
230 * selfname: the way to reinvoke ourselves
231 * exename: executable without the path
232 * function-pointers, which are not implemented in all windows versions
234 static BOOL
init(void)
238 myARGC
= winetest_get_mainargs( &myARGV
);
239 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return FALSE
;
240 strcpy(selfname
, myARGV
[0]);
242 /* Strip the path of selfname */
243 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
244 else exename
= selfname
;
246 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
248 hkernel32
= GetModuleHandleA("kernel32");
249 hntdll
= GetModuleHandleA("ntdll.dll");
251 pNtQueryInformationProcess
= (void *)GetProcAddress(hntdll
, "NtQueryInformationProcess");
252 pNtQueryInformationThread
= (void *)GetProcAddress(hntdll
, "NtQueryInformationThread");
253 pNtQuerySystemInformationEx
= (void *)GetProcAddress(hntdll
, "NtQuerySystemInformationEx");
255 pGetNativeSystemInfo
= (void *) GetProcAddress(hkernel32
, "GetNativeSystemInfo");
256 pGetSystemRegistryQuota
= (void *) GetProcAddress(hkernel32
, "GetSystemRegistryQuota");
257 pIsWow64Process
= (void *) GetProcAddress(hkernel32
, "IsWow64Process");
258 pIsWow64Process2
= (void *) GetProcAddress(hkernel32
, "IsWow64Process2");
259 pQueryFullProcessImageNameA
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameA");
260 pQueryFullProcessImageNameW
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameW");
261 pK32GetProcessImageFileNameA
= (void *) GetProcAddress(hkernel32
, "K32GetProcessImageFileNameA");
262 pCreateJobObjectW
= (void *)GetProcAddress(hkernel32
, "CreateJobObjectW");
263 pOpenJobObjectA
= (void *)GetProcAddress(hkernel32
, "OpenJobObjectA");
264 pAssignProcessToJobObject
= (void *)GetProcAddress(hkernel32
, "AssignProcessToJobObject");
265 pIsProcessInJob
= (void *)GetProcAddress(hkernel32
, "IsProcessInJob");
266 pTerminateJobObject
= (void *)GetProcAddress(hkernel32
, "TerminateJobObject");
267 pQueryInformationJobObject
= (void *)GetProcAddress(hkernel32
, "QueryInformationJobObject");
268 pSetInformationJobObject
= (void *)GetProcAddress(hkernel32
, "SetInformationJobObject");
269 pCreateIoCompletionPort
= (void *)GetProcAddress(hkernel32
, "CreateIoCompletionPort");
270 pGetNumaProcessorNode
= (void *)GetProcAddress(hkernel32
, "GetNumaProcessorNode");
271 pWTSGetActiveConsoleSessionId
= (void *)GetProcAddress(hkernel32
, "WTSGetActiveConsoleSessionId");
272 pCreateToolhelp32Snapshot
= (void *)GetProcAddress(hkernel32
, "CreateToolhelp32Snapshot");
273 pProcess32First
= (void *)GetProcAddress(hkernel32
, "Process32First");
274 pProcess32Next
= (void *)GetProcAddress(hkernel32
, "Process32Next");
275 pThread32First
= (void *)GetProcAddress(hkernel32
, "Thread32First");
276 pThread32Next
= (void *)GetProcAddress(hkernel32
, "Thread32Next");
277 pGetLogicalProcessorInformationEx
= (void *)GetProcAddress(hkernel32
, "GetLogicalProcessorInformationEx");
278 pGetLargePageMinimum
= (void *)GetProcAddress(hkernel32
, "GetLargePageMinimum");
279 pGetSystemCpuSetInformation
= (void *)GetProcAddress(hkernel32
, "GetSystemCpuSetInformation");
280 pInitializeProcThreadAttributeList
= (void *)GetProcAddress(hkernel32
, "InitializeProcThreadAttributeList");
281 pUpdateProcThreadAttribute
= (void *)GetProcAddress(hkernel32
, "UpdateProcThreadAttribute");
282 pDeleteProcThreadAttributeList
= (void *)GetProcAddress(hkernel32
, "DeleteProcThreadAttributeList");
283 pGetActiveProcessorCount
= (void *)GetProcAddress(hkernel32
, "GetActiveProcessorCount");
284 pGetMaximumProcessorCount
= (void *)GetProcAddress(hkernel32
, "GetMaximumProcessorCount");
289 /******************************************************************
292 * generates an absolute file_name for temporary file
295 static void get_file_name(char* buf
)
300 GetTempPathA(sizeof(path
), path
);
301 GetTempFileNameA(path
, "wt", 0, buf
);
304 /******************************************************************
305 * static void childPrintf
308 static void WINAPIV
__WINE_PRINTF_ATTR(2,3) childPrintf(HANDLE h
, const char* fmt
, ...)
311 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
314 va_start(valist
, fmt
);
315 vsprintf(buffer
, fmt
, valist
);
317 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
321 /******************************************************************
324 * output most of the information in the child process
326 static void doChild(const char* file
, const char* option
)
328 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
332 char *ptrA
, *ptrA_save
;
333 WCHAR
*ptrW
, *ptrW_save
;
335 WCHAR bufW
[MAX_PATH
];
336 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
341 if (hFile
== INVALID_HANDLE_VALUE
) return;
343 /* output of startup info (Ansi) */
344 GetStartupInfoA(&siA
);
346 "[StartupInfoA]\ncb=%08lu\nlpDesktop=%s\nlpTitle=%s\n"
347 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
348 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
349 "dwFlags=%lu\nwShowWindow=%u\n"
350 "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n",
351 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
352 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
353 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
354 siA
.dwFlags
, siA
.wShowWindow
,
355 (DWORD_PTR
)siA
.hStdInput
, (DWORD_PTR
)siA
.hStdOutput
, (DWORD_PTR
)siA
.hStdError
);
357 /* check the console handles in the TEB */
358 childPrintf(hFile
, "[TEB]\nhStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n",
359 (DWORD_PTR
)params
->hStdInput
, (DWORD_PTR
)params
->hStdOutput
,
360 (DWORD_PTR
)params
->hStdError
);
362 /* since GetStartupInfoW is only implemented in win2k,
363 * zero out before calling so we can notice the difference
365 memset(&siW
, 0, sizeof(siW
));
366 GetStartupInfoW(&siW
);
368 "[StartupInfoW]\ncb=%08lu\nlpDesktop=%s\nlpTitle=%s\n"
369 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
370 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
371 "dwFlags=%lu\nwShowWindow=%u\n"
372 "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n",
373 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
374 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
375 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
376 siW
.dwFlags
, siW
.wShowWindow
,
377 (DWORD_PTR
)siW
.hStdInput
, (DWORD_PTR
)siW
.hStdOutput
, (DWORD_PTR
)siW
.hStdError
);
380 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
381 for (i
= 0; i
< myARGC
; i
++)
383 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
385 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
386 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
388 /* output toolhelp information */
389 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
390 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %lu\n", GetLastError());
391 memset(&pe
, 0, sizeof(pe
));
392 pe
.dwSize
= sizeof(pe
);
393 if (pProcess32First(snapshot
, &pe
))
395 while (pe
.th32ProcessID
!= GetCurrentProcessId())
396 if (!pProcess32Next(snapshot
, &pe
)) break;
398 CloseHandle(snapshot
);
399 ok(pe
.th32ProcessID
== GetCurrentProcessId(), "failed to find current process in snapshot\n");
401 "[Toolhelp]\ncntUsage=%lu\nth32DefaultHeapID=%Iu\n"
402 "th32ModuleID=%lu\ncntThreads=%lu\nth32ParentProcessID=%lu\n"
403 "pcPriClassBase=%lu\ndwFlags=%lu\nszExeFile=%s\n\n",
404 pe
.cntUsage
, pe
.th32DefaultHeapID
, pe
.th32ModuleID
,
405 pe
.cntThreads
, pe
.th32ParentProcessID
, pe
.pcPriClassBase
,
406 pe
.dwFlags
, encodeA(pe
.szExeFile
));
408 /* output of environment (Ansi) */
409 ptrA_save
= ptrA
= GetEnvironmentStringsA();
412 char env_var
[MAX_LISTED_ENV_VAR
];
414 childPrintf(hFile
, "[EnvironmentA]\n");
418 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
419 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
421 ptrA
+= strlen(ptrA
) + 1;
423 childPrintf(hFile
, "len=%d\n\n", i
);
424 FreeEnvironmentStringsA(ptrA_save
);
427 /* output of environment (Unicode) */
428 ptrW_save
= ptrW
= GetEnvironmentStringsW();
431 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
433 childPrintf(hFile
, "[EnvironmentW]\n");
437 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
438 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
439 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
441 ptrW
+= lstrlenW(ptrW
) + 1;
443 childPrintf(hFile
, "len=%d\n\n", i
);
444 FreeEnvironmentStringsW(ptrW_save
);
447 childPrintf(hFile
, "[Misc]\n");
448 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
449 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
450 if (GetCurrentDirectoryW(ARRAY_SIZE(bufW
), bufW
))
451 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
452 childPrintf(hFile
, "\n");
454 if (option
&& strcmp(option
, "console") == 0)
456 CONSOLE_SCREEN_BUFFER_INFO sbi
;
457 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
458 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
459 DWORD modeIn
, modeOut
;
461 childPrintf(hFile
, "[Console]\n");
462 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
464 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
465 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
466 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
467 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
468 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
469 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
471 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
472 GetConsoleCP(), GetConsoleOutputCP());
473 if (GetConsoleMode(hConIn
, &modeIn
))
474 childPrintf(hFile
, "InputMode=%lu\n", modeIn
);
475 if (GetConsoleMode(hConOut
, &modeOut
))
476 childPrintf(hFile
, "OutputMode=%lu\n", modeOut
);
478 /* now that we have written all relevant information, let's change it */
479 SetLastError(0xdeadbeef);
480 ret
= SetConsoleCP(1252);
481 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
483 win_skip("Setting the codepage is not implemented\n");
487 ok(ret
, "Setting CP\n");
488 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
491 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
492 ok( ret
, "Setting mode (%ld)\n", GetLastError());
493 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
494 ok( ret
, "Setting mode (%ld)\n", GetLastError());
495 sbi
.dwCursorPosition
.X
^= 1;
496 sbi
.dwCursorPosition
.Y
^= 1;
497 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
498 ok( ret
, "Setting cursor position (%ld)\n", GetLastError());
500 if (option
&& strcmp(option
, "stdhandle") == 0)
502 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
503 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
505 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
510 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
511 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
512 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
516 if (option
&& strcmp(option
, "exit_code") == 0)
518 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
526 static char* getChildString(const char* sect
, const char* key
)
528 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
531 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
532 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
533 assert(!(strlen(buf
) & 1));
538 static WCHAR
* getChildStringW(const char* sect
, const char* key
)
540 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
543 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
544 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
545 assert(!(strlen(buf
) & 1));
550 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
552 if (!s1
&& !s2
) return 0;
555 return (sensitive
) ? strcmp(s1
, s2
) : strcasecmp(s1
, s2
);
558 static void ok_child_string( int line
, const char *sect
, const char *key
,
559 const char *expect
, int sensitive
)
561 char* result
= getChildString( sect
, key
);
562 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
563 sect
, key
, expect
? expect
: "(null)", result
);
566 static void ok_child_stringWA( int line
, const char *sect
, const char *key
,
567 const char *expect
, int sensitive
)
572 WCHAR
* result
= getChildStringW( sect
, key
);
574 len
= MultiByteToWideChar( CP_ACP
, 0, expect
, -1, NULL
, 0);
575 expectW
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
576 MultiByteToWideChar( CP_ACP
, 0, expect
, -1, expectW
, len
);
578 len
= WideCharToMultiByte( CP_ACP
, 0, result
, -1, NULL
, 0, NULL
, NULL
);
579 resultA
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(CHAR
));
580 WideCharToMultiByte( CP_ACP
, 0, result
, -1, resultA
, len
, NULL
, NULL
);
583 ok_(__FILE__
, line
)( lstrcmpW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
584 sect
, key
, expect
? expect
: "(null)", resultA
);
586 ok_(__FILE__
, line
)( lstrcmpiW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
587 sect
, key
, expect
? expect
: "(null)", resultA
);
588 HeapFree(GetProcessHeap(),0,expectW
);
589 HeapFree(GetProcessHeap(),0,resultA
);
592 static void ok_child_int( int line
, const char *sect
, const char *key
, UINT expect
)
594 UINT result
= GetPrivateProfileIntA( sect
, key
, !expect
, resfile
);
595 ok_(__FILE__
, line
)( result
== expect
, "%s:%s expected %u, but got %u\n", sect
, key
, expect
, result
);
598 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
599 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
600 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
601 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
603 static void test_Startup(void)
605 char buffer
[2 * MAX_PATH
+ 25];
606 PROCESS_INFORMATION info
;
607 STARTUPINFOA startup
,si
;
609 static CHAR title
[] = "I'm the title string",
610 desktop
[] = "winsta0\\default",
613 /* let's start simplistic */
614 memset(&startup
, 0, sizeof(startup
));
615 startup
.cb
= sizeof(startup
);
616 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
617 startup
.wShowWindow
= SW_SHOWNORMAL
;
619 get_file_name(resfile
);
620 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
621 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
622 wait_and_close_child_process(&info
);
624 reload_child_info(resfile
);
625 GetStartupInfoA(&si
);
626 okChildInt("StartupInfoA", "cb", startup
.cb
);
627 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
628 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
629 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
630 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
631 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
632 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
633 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
634 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
635 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
636 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
638 DeleteFileA(resfile
);
640 /* not so simplistic now */
641 memset(&startup
, 0, sizeof(startup
));
642 startup
.cb
= sizeof(startup
);
643 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
644 startup
.wShowWindow
= SW_SHOWNORMAL
;
645 startup
.lpTitle
= title
;
646 startup
.lpDesktop
= desktop
;
647 startup
.dwXCountChars
= 0x12121212;
648 startup
.dwYCountChars
= 0x23232323;
649 startup
.dwX
= 0x34343434;
650 startup
.dwY
= 0x45454545;
651 startup
.dwXSize
= 0x56565656;
652 startup
.dwYSize
= 0x67676767;
653 startup
.dwFillAttribute
= 0xA55A;
655 get_file_name(resfile
);
656 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
657 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
658 wait_and_close_child_process(&info
);
660 reload_child_info(resfile
);
661 okChildInt("StartupInfoA", "cb", startup
.cb
);
662 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
663 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
664 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
665 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
666 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
667 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
668 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
669 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
670 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
671 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
672 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
674 DeleteFileA(resfile
);
676 /* not so simplistic now */
677 memset(&startup
, 0, sizeof(startup
));
678 startup
.cb
= sizeof(startup
);
679 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
680 startup
.wShowWindow
= SW_SHOWNORMAL
;
681 startup
.lpTitle
= title
;
682 startup
.lpDesktop
= NULL
;
683 startup
.dwXCountChars
= 0x12121212;
684 startup
.dwYCountChars
= 0x23232323;
685 startup
.dwX
= 0x34343434;
686 startup
.dwY
= 0x45454545;
687 startup
.dwXSize
= 0x56565656;
688 startup
.dwYSize
= 0x67676767;
689 startup
.dwFillAttribute
= 0xA55A;
691 get_file_name(resfile
);
692 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
693 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
694 wait_and_close_child_process(&info
);
696 reload_child_info(resfile
);
697 okChildInt("StartupInfoA", "cb", startup
.cb
);
698 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
699 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
700 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
701 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
702 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
703 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
704 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
705 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
706 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
707 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
708 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
710 DeleteFileA(resfile
);
712 /* not so simplistic now */
713 memset(&startup
, 0, sizeof(startup
));
714 startup
.cb
= sizeof(startup
);
715 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
716 startup
.wShowWindow
= SW_SHOWNORMAL
;
717 startup
.lpTitle
= title
;
718 startup
.lpDesktop
= empty
;
719 startup
.dwXCountChars
= 0x12121212;
720 startup
.dwYCountChars
= 0x23232323;
721 startup
.dwX
= 0x34343434;
722 startup
.dwY
= 0x45454545;
723 startup
.dwXSize
= 0x56565656;
724 startup
.dwYSize
= 0x67676767;
725 startup
.dwFillAttribute
= 0xA55A;
727 get_file_name(resfile
);
728 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
729 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
730 wait_and_close_child_process(&info
);
732 reload_child_info(resfile
);
733 okChildInt("StartupInfoA", "cb", startup
.cb
);
734 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
735 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
736 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
737 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
738 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
739 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
740 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
741 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
742 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
743 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
744 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
746 DeleteFileA(resfile
);
748 /* not so simplistic now */
749 memset(&startup
, 0, sizeof(startup
));
750 startup
.cb
= sizeof(startup
);
751 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
752 startup
.wShowWindow
= SW_SHOWNORMAL
;
753 startup
.lpTitle
= NULL
;
754 startup
.lpDesktop
= desktop
;
755 startup
.dwXCountChars
= 0x12121212;
756 startup
.dwYCountChars
= 0x23232323;
757 startup
.dwX
= 0x34343434;
758 startup
.dwY
= 0x45454545;
759 startup
.dwXSize
= 0x56565656;
760 startup
.dwYSize
= 0x67676767;
761 startup
.dwFillAttribute
= 0xA55A;
763 get_file_name(resfile
);
764 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
765 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
766 wait_and_close_child_process(&info
);
768 reload_child_info(resfile
);
769 okChildInt("StartupInfoA", "cb", startup
.cb
);
770 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
771 result
= getChildString( "StartupInfoA", "lpTitle" );
772 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
773 "expected '%s' or null, got '%s'\n", selfname
, result
);
774 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
775 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
776 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
777 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
778 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
779 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
780 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
781 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
782 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
784 DeleteFileA(resfile
);
786 /* not so simplistic now */
787 memset(&startup
, 0, sizeof(startup
));
788 startup
.cb
= sizeof(startup
);
789 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
790 startup
.wShowWindow
= SW_SHOWNORMAL
;
791 startup
.lpTitle
= empty
;
792 startup
.lpDesktop
= desktop
;
793 startup
.dwXCountChars
= 0x12121212;
794 startup
.dwYCountChars
= 0x23232323;
795 startup
.dwX
= 0x34343434;
796 startup
.dwY
= 0x45454545;
797 startup
.dwXSize
= 0x56565656;
798 startup
.dwYSize
= 0x67676767;
799 startup
.dwFillAttribute
= 0xA55A;
801 get_file_name(resfile
);
802 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
803 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
804 wait_and_close_child_process(&info
);
806 reload_child_info(resfile
);
807 okChildInt("StartupInfoA", "cb", startup
.cb
);
808 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
809 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
810 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
811 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
812 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
813 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
814 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
815 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
816 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
817 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
818 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
820 DeleteFileA(resfile
);
822 /* not so simplistic now */
823 memset(&startup
, 0, sizeof(startup
));
824 startup
.cb
= sizeof(startup
);
825 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
826 startup
.wShowWindow
= SW_SHOWNORMAL
;
827 startup
.lpTitle
= empty
;
828 startup
.lpDesktop
= empty
;
829 startup
.dwXCountChars
= 0x12121212;
830 startup
.dwYCountChars
= 0x23232323;
831 startup
.dwX
= 0x34343434;
832 startup
.dwY
= 0x45454545;
833 startup
.dwXSize
= 0x56565656;
834 startup
.dwYSize
= 0x67676767;
835 startup
.dwFillAttribute
= 0xA55A;
837 get_file_name(resfile
);
838 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
839 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
840 wait_and_close_child_process(&info
);
842 reload_child_info(resfile
);
843 okChildInt("StartupInfoA", "cb", startup
.cb
);
844 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
845 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
846 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
847 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
848 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
849 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
850 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
851 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
852 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
853 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
854 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
856 DeleteFileA(resfile
);
858 /* TODO: test for A/W and W/A and W/W */
861 static void test_CommandLine(void)
863 char buffer
[2 * MAX_PATH
+ 65], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
864 char buffer2
[MAX_PATH
+ 44];
865 PROCESS_INFORMATION info
;
866 STARTUPINFOA startup
;
868 LPWSTR cmdline
, cmdline_backup
;
870 memset(&startup
, 0, sizeof(startup
));
871 startup
.cb
= sizeof(startup
);
872 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
873 startup
.wShowWindow
= SW_SHOWNORMAL
;
876 strcpy(buffer
, "\"t:\\NotADir\\NotAFile.exe\"");
877 memset(&info
, 0xa, sizeof(info
));
878 ok(!CreateProcessA(buffer
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess unexpectedly succeeded\n");
879 /* Check that the effective STARTUPINFOA parameters are not modified */
880 ok(startup
.cb
== sizeof(startup
), "unexpected cb %ld\n", startup
.cb
);
881 ok(startup
.lpDesktop
== NULL
, "lpDesktop is not NULL\n");
882 ok(startup
.lpTitle
== NULL
, "lpTitle is not NULL\n");
883 ok(startup
.dwFlags
== STARTF_USESHOWWINDOW
, "unexpected dwFlags %04lx\n", startup
.dwFlags
);
884 ok(startup
.wShowWindow
== SW_SHOWNORMAL
, "unexpected wShowWindow %d\n", startup
.wShowWindow
);
885 ok(!info
.hProcess
, "unexpected hProcess %p\n", info
.hProcess
);
886 ok(!info
.hThread
, "unexpected hThread %p\n", info
.hThread
);
887 ok(!info
.dwProcessId
, "unexpected dwProcessId %04lx\n", info
.dwProcessId
);
888 ok(!info
.dwThreadId
, "unexpected dwThreadId %04lx\n", info
.dwThreadId
);
890 /* the basics; not getting confused by the leading and trailing " */
891 get_file_name(resfile
);
892 sprintf(buffer
, "\"%s\" process dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
893 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
894 /* Check that the effective STARTUPINFOA parameters are not modified */
895 ok(startup
.cb
== sizeof(startup
), "unexpected cb %ld\n", startup
.cb
);
896 ok(startup
.lpDesktop
== NULL
, "lpDesktop is not NULL\n");
897 ok(startup
.lpTitle
== NULL
, "lpTitle is not NULL\n");
898 ok(startup
.dwFlags
== STARTF_USESHOWWINDOW
, "unexpected dwFlags %04lx\n", startup
.dwFlags
);
899 ok(startup
.wShowWindow
== SW_SHOWNORMAL
, "unexpected wShowWindow %d\n", startup
.wShowWindow
);
900 wait_and_close_child_process(&info
);
902 reload_child_info(resfile
);
903 okChildInt("Arguments", "argcA", 5);
904 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
905 okChildString("Arguments", "argvA5", NULL
);
906 okChildString("Arguments", "CommandLineA", buffer
);
908 DeleteFileA(resfile
);
910 /* test main()'s quotes handling */
911 get_file_name(resfile
);
912 sprintf(buffer
, "\"%s\" process dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname
, resfile
);
913 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
914 wait_and_close_child_process(&info
);
916 reload_child_info(resfile
);
917 okChildInt("Arguments", "argcA", 7);
918 okChildString("Arguments", "argvA4", "a\"b\\");
919 okChildString("Arguments", "argvA5", "c\"");
920 okChildString("Arguments", "argvA6", "d");
921 okChildString("Arguments", "argvA7", NULL
);
922 okChildString("Arguments", "CommandLineA", buffer
);
924 DeleteFileA(resfile
);
926 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
927 assert ( lpFilePart
!= 0);
928 *(lpFilePart
-1 ) = 0;
929 SetCurrentDirectoryA( fullpath
);
931 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]
934 get_file_name(resfile
);
935 /* Use exename to avoid buffer containing things like 'C:' */
936 sprintf(buffer
, "./%s process dump \"%s\" \"\"\"\"", exename
, resfile
);
937 SetLastError(0xdeadbeef);
938 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
939 ok(ret
, "CreateProcess (%s) failed : %ld\n", buffer
, GetLastError());
940 wait_and_close_child_process(&info
);
942 reload_child_info(resfile
);
943 sprintf(buffer
, "./%s", exename
);
944 okChildInt("Arguments", "argcA", 5);
945 okChildString("Arguments", "argvA0", buffer
);
946 okChildString("Arguments", "argvA4", "\"");
947 okChildString("Arguments", "argvA5", NULL
);
949 DeleteFileA(resfile
);
951 get_file_name(resfile
);
952 /* Use exename to avoid buffer containing things like 'C:' */
953 sprintf(buffer
, ".\\%s process dump \"%s\"", exename
, resfile
);
954 SetLastError(0xdeadbeef);
955 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
956 ok(ret
, "CreateProcess (%s) failed : %ld\n", buffer
, GetLastError());
957 wait_and_close_child_process(&info
);
959 reload_child_info(resfile
);
960 sprintf(buffer
, ".\\%s", exename
);
961 okChildString("Arguments", "argvA0", buffer
);
963 DeleteFileA(resfile
);
965 get_file_name(resfile
);
966 p
= strrchr(fullpath
, '\\');
967 /* Use exename to avoid buffer containing things like 'C:' */
968 if (p
) sprintf(buffer
, "..%s/%s process dump \"%s\"", p
, exename
, resfile
);
969 else sprintf(buffer
, "./%s process dump \"%s\"", exename
, resfile
);
970 SetLastError(0xdeadbeef);
971 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
972 ok(ret
, "CreateProcess (%s) failed : %ld\n", buffer
, GetLastError());
973 wait_and_close_child_process(&info
);
975 reload_child_info(resfile
);
976 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
977 else sprintf(buffer
, "./%s", exename
);
978 okChildString("Arguments", "argvA0", buffer
);
980 DeleteFileA(resfile
);
983 get_file_name(resfile
);
984 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
985 assert ( lpFilePart
!= 0);
986 *(lpFilePart
-1 ) = 0;
987 p
= strrchr(fullpath
, '\\');
988 /* Use exename to avoid buffer containing things like 'C:' */
989 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
990 else sprintf(buffer
, "./%s", exename
);
991 sprintf(buffer2
, "dummy process dump \"%s\"", resfile
);
992 SetLastError(0xdeadbeef);
993 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
994 ok(ret
, "CreateProcess (%s) failed : %ld\n", buffer
, GetLastError());
995 wait_and_close_child_process(&info
);
997 reload_child_info(resfile
);
998 okChildString("Arguments", "argvA0", "dummy");
999 okChildString("Arguments", "CommandLineA", buffer2
);
1000 okChildStringWA("Arguments", "CommandLineW", buffer2
);
1002 DeleteFileA(resfile
);
1003 SetCurrentDirectoryA( base
);
1005 if (0) /* Test crashes on NT-based Windows. */
1007 /* Test NULL application name and command line parameters. */
1008 SetLastError(0xdeadbeef);
1009 ret
= CreateProcessA(NULL
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1010 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1011 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1012 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
1017 /* Test empty application name parameter. */
1018 SetLastError(0xdeadbeef);
1019 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1020 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1021 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
1022 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
1023 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
1024 "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError());
1028 /* Test empty application name and command line parameters. */
1029 SetLastError(0xdeadbeef);
1030 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1031 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1032 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
1033 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
1034 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
1035 "Expected ERROR_PATH_NOT_FOUND, got %ld\n", GetLastError());
1037 /* Test empty command line parameter. */
1038 SetLastError(0xdeadbeef);
1039 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1040 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1041 ok(GetLastError() == ERROR_FILE_NOT_FOUND
||
1042 GetLastError() == ERROR_PATH_NOT_FOUND
/* NT4 */ ||
1043 GetLastError() == ERROR_BAD_PATHNAME
/* Win98 */ ||
1044 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7 */,
1045 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1047 strcpy(buffer
, "doesnotexist.exe");
1048 strcpy(buffer2
, "does not exist.exe");
1050 /* Test nonexistent application name. */
1051 SetLastError(0xdeadbeef);
1052 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1053 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1054 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1056 SetLastError(0xdeadbeef);
1057 ret
= CreateProcessA(buffer2
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1058 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1059 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1061 /* Test nonexistent command line parameter. */
1062 SetLastError(0xdeadbeef);
1063 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1064 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1065 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1067 SetLastError(0xdeadbeef);
1068 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1069 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1070 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
1072 /* Test whether GetCommandLineW reads directly from TEB or from a cached address */
1073 cmdline
= GetCommandLineW();
1074 ok(cmdline
== NtCurrentTeb()->Peb
->ProcessParameters
->CommandLine
.Buffer
, "Expected address from TEB, got %p\n", cmdline
);
1076 cmdline_backup
= cmdline
;
1077 NtCurrentTeb()->Peb
->ProcessParameters
->CommandLine
.Buffer
= NULL
;
1078 cmdline
= GetCommandLineW();
1079 ok(cmdline
== cmdline_backup
, "Expected cached address from TEB, got %p\n", cmdline
);
1080 NtCurrentTeb()->Peb
->ProcessParameters
->CommandLine
.Buffer
= cmdline_backup
;
1083 static void test_Directory(void)
1085 char buffer
[2 * MAX_PATH
+ 25];
1086 PROCESS_INFORMATION info
;
1087 STARTUPINFOA startup
;
1088 char windir
[MAX_PATH
];
1089 static CHAR cmdline
[] = "winver.exe";
1091 memset(&startup
, 0, sizeof(startup
));
1092 startup
.cb
= sizeof(startup
);
1093 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1094 startup
.wShowWindow
= SW_SHOWNORMAL
;
1097 get_file_name(resfile
);
1098 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
1099 GetWindowsDirectoryA( windir
, sizeof(windir
) );
1100 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
1101 wait_and_close_child_process(&info
);
1103 reload_child_info(resfile
);
1104 okChildIString("Misc", "CurrDirA", windir
);
1106 DeleteFileA(resfile
);
1108 /* search PATH for the exe if directory is NULL */
1109 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1110 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
1111 CloseHandle(info
.hThread
);
1112 CloseHandle(info
.hProcess
);
1114 /* if any directory is provided, don't search PATH, error on bad directory */
1115 SetLastError(0xdeadbeef);
1116 memset(&info
, 0, sizeof(info
));
1117 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
1118 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
1119 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %ld\n", GetLastError());
1120 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
1123 static void test_Toolhelp(void)
1125 char buffer
[2 * MAX_PATH
+ 27];
1126 STARTUPINFOA startup
;
1127 PROCESS_INFORMATION info
;
1128 HANDLE process
, thread
, snapshot
;
1135 memset(&startup
, 0, sizeof(startup
));
1136 startup
.cb
= sizeof(startup
);
1137 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1138 startup
.wShowWindow
= SW_SHOWNORMAL
;
1140 get_file_name(resfile
);
1141 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
1142 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1143 wait_and_close_child_process(&info
);
1145 reload_child_info(resfile
);
1146 okChildInt("Toolhelp", "cntUsage", 0);
1147 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1148 okChildInt("Toolhelp", "th32ModuleID", 0);
1149 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1150 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1151 okChildInt("Toolhelp", "dwFlags", 0);
1154 DeleteFileA(resfile
);
1156 get_file_name(resfile
);
1157 sprintf(buffer
, "\"%s\" process nested \"%s\"", selfname
, resfile
);
1158 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1159 wait_child_process(info
.hProcess
);
1161 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1162 ok(process
!= NULL
, "OpenProcess failed %lu\n", GetLastError());
1163 CloseHandle(process
);
1165 CloseHandle(info
.hProcess
);
1166 CloseHandle(info
.hThread
);
1168 for (i
= 0; i
< 20; i
++)
1170 SetLastError(0xdeadbeef);
1171 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1172 ok(process
|| GetLastError() == ERROR_INVALID_PARAMETER
, "OpenProcess failed %lu\n", GetLastError());
1173 if (!process
) break;
1174 CloseHandle(process
);
1177 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1178 ok(i
< 20 || broken(i
== 20), "process object not released\n");
1180 /* Look for the nested process by pid */
1181 reload_child_info(resfile
);
1182 nested_pid
= GetPrivateProfileIntA("Nested", "Pid", 0, resfile
);
1183 DeleteFileA(resfile
);
1185 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
1186 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %lu\n", GetLastError());
1187 memset(&pe
, 0, sizeof(pe
));
1188 pe
.dwSize
= sizeof(pe
);
1189 if (pProcess32First(snapshot
, &pe
))
1191 while (pe
.th32ProcessID
!= nested_pid
)
1192 if (!pProcess32Next(snapshot
, &pe
)) break;
1194 CloseHandle(snapshot
);
1195 ok(pe
.th32ProcessID
== nested_pid
, "failed to find nested child process\n");
1196 ok(pe
.th32ParentProcessID
== info
.dwProcessId
, "nested child process has parent %lu instead of %lu\n", pe
.th32ParentProcessID
, info
.dwProcessId
);
1197 ok(stricmp(pe
.szExeFile
, exename
) == 0, "nested executable is %s instead of %s\n", pe
.szExeFile
, exename
);
1199 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, pe
.th32ProcessID
);
1200 ok(process
!= NULL
, "OpenProcess failed %lu\n", GetLastError());
1202 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD
, 0);
1203 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %lu\n", GetLastError());
1204 memset(&te
, 0, sizeof(te
));
1205 te
.dwSize
= sizeof(te
);
1206 if (pThread32First(snapshot
, &te
))
1208 while (te
.th32OwnerProcessID
!= pe
.th32ProcessID
)
1209 if (!pThread32Next(snapshot
, &te
)) break;
1211 CloseHandle(snapshot
);
1212 ok(te
.th32OwnerProcessID
== pe
.th32ProcessID
, "failed to find suspended thread\n");
1214 thread
= OpenThread(THREAD_ALL_ACCESS_NT4
, FALSE
, te
.th32ThreadID
);
1215 ok(thread
!= NULL
, "OpenThread failed %lu\n", GetLastError());
1216 ret
= ResumeThread(thread
);
1217 ok(ret
== 1, "expected 1, got %lu\n", ret
);
1218 CloseHandle(thread
);
1220 wait_child_process(process
);
1221 CloseHandle(process
);
1223 reload_child_info(resfile
);
1224 okChildInt("Toolhelp", "cntUsage", 0);
1225 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1226 okChildInt("Toolhelp", "th32ModuleID", 0);
1227 okChildInt("Toolhelp", "th32ParentProcessID", info
.dwProcessId
);
1228 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1229 okChildInt("Toolhelp", "dwFlags", 0);
1232 DeleteFileA(resfile
);
1235 static BOOL
is_str_env_drive_dir(const char* str
)
1237 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1238 str
[3] == '=' && str
[4] == str
[1];
1241 /* compared expected child's environment (in gesA) from actual
1242 * environment our child got
1244 static void cmpEnvironment(const char* gesA
)
1252 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1254 /* now look each parent env in child */
1255 if ((ptrA
= gesA
) != NULL
)
1259 for (i
= 0; i
< clen
; i
++)
1261 sprintf(key
, "env%d", i
);
1262 res
= getChildString("EnvironmentA", key
);
1263 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1267 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1269 ptrA
+= strlen(ptrA
) + 1;
1273 /* and each child env in parent */
1274 for (i
= 0; i
< clen
; i
++)
1276 sprintf(key
, "env%d", i
);
1277 res
= getChildString("EnvironmentA", key
);
1278 if ((ptrA
= gesA
) != NULL
)
1282 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1284 ptrA
+= strlen(ptrA
) + 1;
1286 if (!*ptrA
) ptrA
= NULL
;
1289 if (!is_str_env_drive_dir(res
))
1291 found
= ptrA
!= NULL
;
1292 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1294 /* else => should also test we get the right per drive default directory here... */
1298 static void test_Environment(void)
1300 char buffer
[2 * MAX_PATH
+ 25];
1301 PROCESS_INFORMATION info
;
1302 STARTUPINFOA startup
;
1310 memset(&startup
, 0, sizeof(startup
));
1311 startup
.cb
= sizeof(startup
);
1312 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1313 startup
.wShowWindow
= SW_SHOWNORMAL
;
1316 get_file_name(resfile
);
1317 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
1318 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1319 wait_and_close_child_process(&info
);
1321 reload_child_info(resfile
);
1322 env
= GetEnvironmentStringsA();
1323 cmpEnvironment(env
);
1325 DeleteFileA(resfile
);
1327 memset(&startup
, 0, sizeof(startup
));
1328 startup
.cb
= sizeof(startup
);
1329 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1330 startup
.wShowWindow
= SW_SHOWNORMAL
;
1333 get_file_name(resfile
);
1334 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
1340 slen
= strlen(ptr
)+1;
1341 child_env_len
+= slen
;
1344 /* Add space for additional environment variables */
1345 child_env_len
+= 256;
1346 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1349 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1350 ptr
+= strlen(ptr
) + 1;
1351 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1352 ptr
+= strlen(ptr
) + 1;
1353 strcpy(ptr
, "FOO=BAR");
1354 ptr
+= strlen(ptr
) + 1;
1355 strcpy(ptr
, "BAR=FOOBAR");
1356 ptr
+= strlen(ptr
) + 1;
1357 /* copy all existing variables except:
1358 * - PATH (already set above)
1359 * - the directory definitions (=[A-Z]:=)
1361 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1363 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1364 !is_str_env_drive_dir(ptr2
))
1367 ptr
+= strlen(ptr
) + 1;
1371 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1372 wait_and_close_child_process(&info
);
1374 reload_child_info(resfile
);
1375 cmpEnvironment(child_env
);
1377 HeapFree(GetProcessHeap(), 0, child_env
);
1378 FreeEnvironmentStringsA(env
);
1380 DeleteFileA(resfile
);
1383 static void test_SuspendFlag(void)
1385 char buffer
[2 * MAX_PATH
+ 25];
1386 PROCESS_INFORMATION info
;
1387 STARTUPINFOA startup
, us
;
1391 /* let's start simplistic */
1392 memset(&startup
, 0, sizeof(startup
));
1393 startup
.cb
= sizeof(startup
);
1394 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1395 startup
.wShowWindow
= SW_SHOWNORMAL
;
1397 get_file_name(resfile
);
1398 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
1399 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1401 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1403 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1404 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1406 wait_and_close_child_process(&info
);
1408 GetStartupInfoA(&us
);
1410 reload_child_info(resfile
);
1411 okChildInt("StartupInfoA", "cb", startup
.cb
);
1412 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1413 result
= getChildString( "StartupInfoA", "lpTitle" );
1414 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1415 "expected '%s' or null, got '%s'\n", selfname
, result
);
1416 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1417 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1418 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1419 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1420 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1421 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1422 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1423 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1424 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1426 DeleteFileA(resfile
);
1429 static void test_DebuggingFlag(void)
1431 char buffer
[2 * MAX_PATH
+ 25];
1432 void *processbase
= NULL
;
1433 PROCESS_INFORMATION info
;
1434 STARTUPINFOA startup
, us
;
1439 /* let's start simplistic */
1440 memset(&startup
, 0, sizeof(startup
));
1441 startup
.cb
= sizeof(startup
);
1442 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1443 startup
.wShowWindow
= SW_SHOWNORMAL
;
1445 get_file_name(resfile
);
1446 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
1447 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1449 /* get all startup events up to the entry point break exception */
1452 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1453 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1456 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1457 "first event: %ld\n", de
.dwDebugEventCode
);
1458 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1460 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1461 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1462 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1463 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1465 ok(dbg
, "I have seen a debug event\n");
1466 wait_and_close_child_process(&info
);
1468 GetStartupInfoA(&us
);
1470 reload_child_info(resfile
);
1471 okChildInt("StartupInfoA", "cb", startup
.cb
);
1472 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1473 result
= getChildString( "StartupInfoA", "lpTitle" );
1474 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1475 "expected '%s' or null, got '%s'\n", selfname
, result
);
1476 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1477 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1478 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1479 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1480 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1481 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1482 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1483 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1484 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1486 DeleteFileA(resfile
);
1489 static void test_Console(void)
1491 char buffer
[2 * MAX_PATH
+ 35];
1492 PROCESS_INFORMATION info
;
1493 STARTUPINFOA startup
, us
;
1494 SECURITY_ATTRIBUTES sa
;
1495 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1496 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1497 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1499 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1500 const char* msg
= "This is a std-handle inheritance test.";
1502 BOOL run_tests
= TRUE
;
1505 memset(&startup
, 0, sizeof(startup
));
1506 startup
.cb
= sizeof(startup
);
1507 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1508 startup
.wShowWindow
= SW_SHOWNORMAL
;
1510 sa
.nLength
= sizeof(sa
);
1511 sa
.lpSecurityDescriptor
= NULL
;
1512 sa
.bInheritHandle
= TRUE
;
1514 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1515 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1517 /* first, we need to be sure we're attached to a console */
1518 if (startup
.hStdInput
== INVALID_HANDLE_VALUE
|| startup
.hStdOutput
== INVALID_HANDLE_VALUE
)
1520 /* this fails either when this test process is run detached from console
1521 * (unlikely, as this very process must be explicitly created with detached flag),
1522 * or is attached to a Wine's shell-no-window kind of console (if the later, detach from it)
1525 /* we're not attached to a console, let's do it */
1527 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1528 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1530 /* now verify everything's ok */
1531 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1532 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1533 startup
.hStdError
= startup
.hStdOutput
;
1535 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1536 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
), "Getting console in mode\n");
1537 ok(GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console out mode\n");
1538 cpIn
= GetConsoleCP();
1539 cpOut
= GetConsoleOutputCP();
1541 get_file_name(resfile
);
1542 sprintf(buffer
, "\"%s\" process dump \"%s\" console", selfname
, resfile
);
1543 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1544 wait_and_close_child_process(&info
);
1546 reload_child_info(resfile
);
1547 /* now get the modification the child has made, and resets parents expected values */
1548 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1549 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
), "Getting console in mode\n");
1550 ok(GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console out mode\n");
1552 SetConsoleMode(startup
.hStdInput
, modeIn
);
1553 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1555 /* don't test flag that is changed at startup if WINETEST_COLOR is set */
1556 modeOut
= (modeOut
& ~ENABLE_VIRTUAL_TERMINAL_PROCESSING
) |
1557 (modeOutC
& ENABLE_VIRTUAL_TERMINAL_PROCESSING
);
1559 cpInC
= GetConsoleCP();
1560 cpOutC
= GetConsoleOutputCP();
1562 /* Try to set invalid CP */
1563 SetLastError(0xdeadbeef);
1564 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1565 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1566 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1567 "GetLastError: expecting %u got %lu\n",
1568 ERROR_INVALID_PARAMETER
, GetLastError());
1569 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1573 SetLastError(0xdeadbeef);
1574 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1575 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1576 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1577 "GetLastError: expecting %u got %lu\n",
1578 ERROR_INVALID_PARAMETER
, GetLastError());
1581 SetConsoleOutputCP(cpOut
);
1583 GetStartupInfoA(&us
);
1585 okChildInt("StartupInfoA", "cb", startup
.cb
);
1586 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1587 result
= getChildString( "StartupInfoA", "lpTitle" );
1588 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1589 "expected '%s' or null, got '%s'\n", selfname
, result
);
1590 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1591 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1592 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1593 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1594 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1595 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1596 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1597 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1598 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1600 /* check child correctly inherited the console */
1601 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1602 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1603 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1604 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1605 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1606 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1607 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1608 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1609 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1610 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1611 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1612 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1613 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1614 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1615 okChildInt("Console", "InputCP", cpIn
);
1616 okChildInt("Console", "OutputCP", cpOut
);
1617 okChildInt("Console", "InputMode", modeIn
);
1618 okChildInt("Console", "OutputMode", modeOut
);
1622 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %ld/%ld)\n", cpInC
, cpIn
);
1623 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %ld/%ld)\n", cpOutC
, cpOut
);
1626 win_skip("Setting the codepage is not implemented\n");
1628 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1629 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1632 DeleteFileA(resfile
);
1634 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1635 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1636 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1637 "Duplicating as inheritable child-output pipe\n");
1638 CloseHandle(hChildOut
);
1640 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1641 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1642 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1643 "Duplicating as inheritable child-input pipe\n");
1644 CloseHandle(hChildIn
);
1646 memset(&startup
, 0, sizeof(startup
));
1647 startup
.cb
= sizeof(startup
);
1648 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1649 startup
.wShowWindow
= SW_SHOWNORMAL
;
1650 startup
.hStdInput
= hChildInInh
;
1651 startup
.hStdOutput
= hChildOutInh
;
1652 startup
.hStdError
= hChildOutInh
;
1654 get_file_name(resfile
);
1655 sprintf(buffer
, "\"%s\" process dump \"%s\" stdhandle", selfname
, resfile
);
1656 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1657 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1658 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1660 msg_len
= strlen(msg
) + 1;
1661 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1662 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %lu\n", msg_len
, w
);
1663 memset(buffer
, 0, sizeof(buffer
));
1664 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1665 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1667 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1668 ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
);
1670 wait_and_close_child_process(&info
);
1672 reload_child_info(resfile
);
1673 okChildString("StdHandle", "msg", msg
);
1676 DeleteFileA(resfile
);
1679 static void test_ExitCode(void)
1681 char buffer
[2 * MAX_PATH
+ 35];
1682 PROCESS_INFORMATION info
;
1683 STARTUPINFOA startup
;
1686 /* let's start simplistic */
1687 memset(&startup
, 0, sizeof(startup
));
1688 startup
.cb
= sizeof(startup
);
1689 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1690 startup
.wShowWindow
= SW_SHOWNORMAL
;
1692 get_file_name(resfile
);
1693 sprintf(buffer
, "\"%s\" process dump \"%s\" exit_code", selfname
, resfile
);
1694 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1696 /* not wait_child_process() because of the exit code */
1697 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1699 reload_child_info(resfile
);
1700 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1701 okChildInt("ExitCode", "value", code
);
1704 DeleteFileA(resfile
);
1707 static void test_OpenProcess(void)
1711 MEMORY_BASIC_INFORMATION info
;
1712 SIZE_T dummy
, read_bytes
;
1715 /* without PROCESS_VM_OPERATION */
1716 hproc
= OpenProcess(PROCESS_ALL_ACCESS_NT4
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1717 ok(hproc
!= NULL
, "OpenProcess error %ld\n", GetLastError());
1719 SetLastError(0xdeadbeef);
1720 addr1
= VirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1721 ok(!addr1
, "VirtualAllocEx should fail\n");
1722 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1725 win_skip("VirtualAllocEx not implemented\n");
1728 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %ld\n", GetLastError());
1730 read_bytes
= 0xdeadbeef;
1731 SetLastError(0xdeadbeef);
1732 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1733 ok(ret
, "ReadProcessMemory error %ld\n", GetLastError());
1734 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %Id\n", read_bytes
);
1738 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1739 ok(hproc
!= NULL
, "OpenProcess error %ld\n", GetLastError());
1741 addr1
= VirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1742 ok(addr1
!= NULL
, "VirtualAllocEx error %ld\n", GetLastError());
1744 /* without PROCESS_QUERY_INFORMATION */
1745 SetLastError(0xdeadbeef);
1746 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1747 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1748 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %ld\n", GetLastError());
1750 /* without PROCESS_VM_READ */
1751 read_bytes
= 0xdeadbeef;
1752 SetLastError(0xdeadbeef);
1753 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1754 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1755 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %ld\n", GetLastError());
1756 ok(read_bytes
== 0, "wrong read bytes %Id\n", read_bytes
);
1760 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1762 memset(&info
, 0xcc, sizeof(info
));
1763 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1764 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %ld\n", GetLastError());
1766 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1767 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1768 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%lx != PAGE_NOACCESS\n", info
.AllocationProtect
);
1769 ok(info
.RegionSize
== 0x10000, "%Ix != 0x10000\n", info
.RegionSize
);
1770 ok(info
.State
== MEM_RESERVE
, "%lx != MEM_RESERVE\n", info
.State
);
1771 /* NT reports Protect == 0 for a not committed memory block */
1772 ok(info
.Protect
== 0 /* NT */ ||
1773 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1774 "%lx != PAGE_NOACCESS\n", info
.Protect
);
1775 ok(info
.Type
== MEM_PRIVATE
, "%lx != MEM_PRIVATE\n", info
.Type
);
1777 SetLastError(0xdeadbeef);
1778 ok(!VirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1779 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1780 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %ld\n", GetLastError());
1784 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
1787 SetLastError(0xdeadbeef);
1788 memset(&info
, 0xcc, sizeof(info
));
1789 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1790 if (read_bytes
) /* win8 */
1792 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %ld\n", GetLastError());
1793 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1794 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1795 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%lx != PAGE_NOACCESS\n", info
.AllocationProtect
);
1796 ok(info
.RegionSize
== 0x10000, "%Ix != 0x10000\n", info
.RegionSize
);
1797 ok(info
.State
== MEM_RESERVE
, "%lx != MEM_RESERVE\n", info
.State
);
1798 ok(info
.Protect
== 0, "%lx != PAGE_NOACCESS\n", info
.Protect
);
1799 ok(info
.Type
== MEM_PRIVATE
, "%lx != MEM_PRIVATE\n", info
.Type
);
1801 else /* before win8 */
1802 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %ld\n", GetLastError());
1804 SetLastError(0xdeadbeef);
1805 ok(!VirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1806 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1807 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %ld\n", GetLastError());
1812 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1815 static void test_GetProcessVersion(void)
1817 static char cmdline
[] = "winver.exe";
1818 PROCESS_INFORMATION pi
;
1822 SetLastError(0xdeadbeef);
1823 ret
= GetProcessVersion(0);
1824 ok(ret
, "GetProcessVersion error %lu\n", GetLastError());
1826 SetLastError(0xdeadbeef);
1827 ret
= GetProcessVersion(GetCurrentProcessId());
1828 ok(ret
, "GetProcessVersion error %lu\n", GetLastError());
1830 memset(&si
, 0, sizeof(si
));
1832 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1833 si
.wShowWindow
= SW_HIDE
;
1834 SetLastError(0xdeadbeef);
1835 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1836 ok(ret
, "CreateProcess error %lu\n", GetLastError());
1838 SetLastError(0xdeadbeef);
1839 ret
= GetProcessVersion(pi
.dwProcessId
);
1840 ok(ret
, "GetProcessVersion error %lu\n", GetLastError());
1842 SetLastError(0xdeadbeef);
1843 ret
= TerminateProcess(pi
.hProcess
, 0);
1844 ok(ret
, "TerminateProcess error %lu\n", GetLastError());
1846 CloseHandle(pi
.hProcess
);
1847 CloseHandle(pi
.hThread
);
1850 static void test_GetProcessImageFileNameA(void)
1853 CHAR process
[MAX_PATH
];
1854 static const char harddisk
[] = "\\Device\\HarddiskVolume";
1856 if (!pK32GetProcessImageFileNameA
)
1858 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1862 /* callers must guess the buffer size */
1863 SetLastError(0xdeadbeef);
1864 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL
, 0);
1865 ok(!rc
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
1866 "K32GetProcessImageFileNameA(no buffer): returned %lu, le=%lu\n", rc
, GetLastError());
1869 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), process
, sizeof(process
));
1870 expect_eq_d(rc
, lstrlenA(process
));
1871 if (strncmp(process
, harddisk
, lstrlenA(harddisk
)))
1873 todo_wine
win_skip("%s is probably on a network share, skipping tests\n", process
);
1877 if (!pQueryFullProcessImageNameA
)
1878 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1881 CHAR image
[MAX_PATH
];
1884 length
= sizeof(image
);
1885 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE
, image
, &length
));
1886 expect_eq_d(length
, lstrlenA(image
));
1887 ok(lstrcmpiA(process
, image
) == 0, "expected '%s' to be equal to '%s'\n", process
, image
);
1891 static void test_QueryFullProcessImageNameA(void)
1893 #define INIT_STR "Just some words"
1895 CHAR buf
[MAX_PATH
], module
[MAX_PATH
];
1897 if (!pQueryFullProcessImageNameA
)
1899 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1904 SetLastError(0); /* old Windows don't reset it on success */
1905 size
= GetModuleFileNameA(NULL
, module
, sizeof(module
));
1906 ok(size
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
, "GetModuleFileName failed: %lu le=%lu\n", size
, GetLastError());
1908 /* get the buffer length without \0 terminator */
1909 length
= sizeof(buf
);
1910 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1911 expect_eq_d(length
, lstrlenA(buf
));
1912 ok((buf
[0] == '\\' && buf
[1] == '\\') ||
1913 lstrcmpiA(buf
, module
) == 0, "expected %s to match %s\n", buf
, module
);
1915 /* when the buffer is too small
1916 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1917 * - the size variable is not modified
1918 * tested with the biggest too small size
1921 sprintf(buf
,INIT_STR
);
1922 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1923 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1924 expect_eq_d(length
, size
);
1925 expect_eq_s(INIT_STR
, buf
);
1927 /* retest with smaller buffer size
1930 sprintf(buf
,INIT_STR
);
1931 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1932 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1933 expect_eq_d(4, size
);
1934 expect_eq_s(INIT_STR
, buf
);
1936 /* this is a difference between the ansi and the unicode version
1937 * the unicode version crashes when the size is big enough to hold
1938 * the result while the ansi version throws an error
1941 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1942 expect_eq_d(1024, size
);
1943 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1946 static void test_QueryFullProcessImageNameW(void)
1949 WCHAR module_name
[1024], device
[1024];
1950 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
1955 if (!pQueryFullProcessImageNameW
)
1957 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1961 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1963 /* GetCurrentProcess pseudo-handle */
1964 size
= ARRAY_SIZE(buf
);
1965 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
1966 expect_eq_d(lstrlenW(buf
), size
);
1967 expect_eq_ws_i(buf
, module_name
);
1969 hSelf
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
1971 size
= ARRAY_SIZE(buf
);
1972 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1973 expect_eq_d(lstrlenW(buf
), size
);
1974 expect_eq_ws_i(buf
, module_name
);
1976 /* Buffer too small */
1977 size
= lstrlenW(module_name
)/2;
1978 lstrcpyW(buf
, deviceW
);
1979 SetLastError(0xdeadbeef);
1980 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1981 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1982 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1983 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
1985 /* Too small - not space for NUL terminator */
1986 size
= lstrlenW(module_name
);
1987 SetLastError(0xdeadbeef);
1988 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1989 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
1990 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1994 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
1995 expect_eq_d(0, size
);
1996 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1998 /* Buffer too small */
1999 size
= lstrlenW(module_name
)/2;
2000 SetLastError(0xdeadbeef);
2001 lstrcpyW(buf
, module_name
);
2002 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
2003 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
2004 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2005 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
2007 /* Invalid flags - a few arbitrary values only */
2008 for (flags
= 2; flags
<= 15; ++flags
)
2010 size
= ARRAY_SIZE(buf
);
2011 SetLastError(0xdeadbeef);
2012 *(DWORD
*)buf
= 0x13579acf;
2015 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, flags
, buf
, &size
));
2016 expect_eq_d((DWORD
)ARRAY_SIZE(buf
), size
); /* size not changed */
2017 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
2018 expect_eq_d(0x13579acf, *(DWORD
*)buf
); /* buffer not changed */
2021 for (flags
= 16; flags
!= 0; flags
<<= 1)
2023 size
= ARRAY_SIZE(buf
);
2024 SetLastError(0xdeadbeef);
2025 *(DWORD
*)buf
= 0x13579acf;
2028 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, flags
, buf
, &size
));
2029 expect_eq_d((DWORD
)ARRAY_SIZE(buf
), size
); /* size not changed */
2030 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
2031 expect_eq_d(0x13579acf, *(DWORD
*)buf
); /* buffer not changed */
2036 size
= ARRAY_SIZE(buf
);
2037 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
2038 expect_eq_d(lstrlenW(buf
), size
);
2039 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
2040 ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
2042 module_name
[2] = '\0';
2044 size
= QueryDosDeviceW(module_name
, device
, ARRAY_SIZE(device
));
2045 ok(size
, "QueryDosDeviceW failed: le=%lu\n", GetLastError());
2046 len
= lstrlenW(device
);
2047 ok(size
>= len
+2, "expected %ld to be greater than %ld+2 = strlen(%s)\n", size
, len
, wine_dbgstr_w(device
));
2049 if (size
>= lstrlenW(buf
))
2051 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2055 ok(buf
[len
] == '\\', "expected '%c' to be a '\\' in %s\n", buf
[len
], wine_dbgstr_w(module_name
));
2057 ok(lstrcmpiW(device
, buf
) == 0, "expected %s to match %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2058 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));
2064 static void test_Handles(void)
2066 HANDLE handle
= GetCurrentProcess();
2071 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
2072 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
2073 "invalid current process handle %p\n", handle
);
2074 ret
= GetExitCodeProcess( handle
, &code
);
2075 ok( ret
, "GetExitCodeProcess failed err %lu\n", GetLastError() );
2077 /* truncated handle */
2078 SetLastError( 0xdeadbeef );
2079 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
2080 ret
= GetExitCodeProcess( handle
, &code
);
2081 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2082 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %lu\n", GetLastError() );
2083 /* sign-extended handle */
2084 SetLastError( 0xdeadbeef );
2085 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
2086 ret
= GetExitCodeProcess( handle
, &code
);
2087 ok( ret
, "GetExitCodeProcess failed err %lu\n", GetLastError() );
2088 /* invalid high-word */
2089 SetLastError( 0xdeadbeef );
2090 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
2091 ret
= GetExitCodeProcess( handle
, &code
);
2092 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2093 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %lu\n", GetLastError() );
2096 handle
= GetStdHandle( STD_ERROR_HANDLE
);
2097 ok( handle
!= 0, "handle %p\n", handle
);
2098 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
2099 0, TRUE
, DUPLICATE_SAME_ACCESS
);
2100 SetStdHandle( STD_ERROR_HANDLE
, h3
);
2101 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
2102 h2
= GetStdHandle( STD_ERROR_HANDLE
);
2104 broken( h2
== h3
) || /* nt4, w2k */
2105 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
2106 "wrong handle %p/%p\n", h2
, h3
);
2107 SetStdHandle( STD_ERROR_HANDLE
, handle
);
2110 static void test_IsWow64Process(void)
2112 PROCESS_INFORMATION pi
;
2116 static char cmdline
[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2117 static char cmdline_wow64
[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2119 if (!pIsWow64Process
)
2121 win_skip("IsWow64Process is not available\n");
2125 memset(&si
, 0, sizeof(si
));
2127 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2128 si
.wShowWindow
= SW_HIDE
;
2129 ret
= CreateProcessA(NULL
, cmdline_wow64
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2132 trace("Created process %s\n", cmdline_wow64
);
2134 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2135 ok(ret
, "IsWow64Process failed.\n");
2136 ok(is_wow64
, "is_wow64 returned FALSE.\n");
2138 ret
= TerminateProcess(pi
.hProcess
, 0);
2139 ok(ret
, "TerminateProcess error\n");
2141 CloseHandle(pi
.hProcess
);
2142 CloseHandle(pi
.hThread
);
2145 memset(&si
, 0, sizeof(si
));
2147 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2148 si
.wShowWindow
= SW_HIDE
;
2149 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2152 trace("Created process %s\n", cmdline
);
2154 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2155 ok(ret
, "IsWow64Process failed.\n");
2156 ok(!is_wow64
, "is_wow64 returned TRUE.\n");
2158 ret
= TerminateProcess(pi
.hProcess
, 0);
2159 ok(ret
, "TerminateProcess error\n");
2161 CloseHandle(pi
.hProcess
);
2162 CloseHandle(pi
.hThread
);
2166 static void test_IsWow64Process2(void)
2168 PROCESS_INFORMATION pi
;
2171 USHORT machine
, native_machine
;
2172 static char cmdline
[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2173 static char cmdline_wow64
[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2175 USHORT expect_native
= IMAGE_FILE_MACHINE_I386
;
2176 #elif defined __x86_64__
2177 USHORT expect_native
= IMAGE_FILE_MACHINE_AMD64
;
2178 #elif defined __arm__
2179 USHORT expect_native
= IMAGE_FILE_MACHINE_ARMNT
;
2180 #elif defined __aarch64__
2181 USHORT expect_native
= IMAGE_FILE_MACHINE_ARM64
;
2183 USHORT expect_native
= 0;
2186 if (!pIsWow64Process2
)
2188 win_skip("IsWow64Process2 is not available\n");
2192 memset(&si
, 0, sizeof(si
));
2194 SetLastError(0xdeadbeef);
2195 ret
= CreateProcessA(cmdline_wow64
, NULL
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2198 SetLastError(0xdeadbeef);
2199 machine
= native_machine
= 0xdead;
2200 ret
= pIsWow64Process2(pi
.hProcess
, &machine
, &native_machine
);
2201 ok(ret
, "IsWow64Process2 error %lu\n", GetLastError());
2203 #if defined(__i386__) || defined(__x86_64__)
2204 ok(machine
== IMAGE_FILE_MACHINE_I386
, "got %#x\n", machine
);
2205 ok( native_machine
== IMAGE_FILE_MACHINE_AMD64
||
2206 native_machine
== IMAGE_FILE_MACHINE_ARM64
, "got %#x\n", native_machine
);
2207 expect_native
= native_machine
;
2209 skip("not supported architecture\n");
2211 ret
= TerminateProcess(pi
.hProcess
, 0);
2212 ok(ret
, "TerminateProcess error\n");
2214 CloseHandle(pi
.hProcess
);
2215 CloseHandle(pi
.hThread
);
2218 memset(&si
, 0, sizeof(si
));
2220 SetLastError(0xdeadbeef);
2221 ret
= CreateProcessA(cmdline
, NULL
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2222 ok(ret
, "CreateProcess error %lu\n", GetLastError());
2224 SetLastError(0xdeadbeef);
2225 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2226 ok(ret
, "IsWow64Process error %lu\n", GetLastError());
2228 SetLastError(0xdeadbeef);
2229 machine
= native_machine
= 0xdead;
2230 ret
= pIsWow64Process2(pi
.hProcess
, &machine
, &native_machine
);
2231 ok(ret
, "IsWow64Process2 error %lu\n", GetLastError());
2233 ok(machine
== IMAGE_FILE_MACHINE_UNKNOWN
, "got %#x\n", machine
);
2234 ok(native_machine
== expect_native
, "got %#x\n", native_machine
);
2236 SetLastError(0xdeadbeef);
2238 ret
= pIsWow64Process2(pi
.hProcess
, &machine
, NULL
);
2239 ok(ret
, "IsWow64Process2 error %lu\n", GetLastError());
2240 ok(machine
== IMAGE_FILE_MACHINE_UNKNOWN
, "got %#x\n", machine
);
2242 ret
= TerminateProcess(pi
.hProcess
, 0);
2243 ok(ret
, "TerminateProcess error\n");
2245 CloseHandle(pi
.hProcess
);
2246 CloseHandle(pi
.hThread
);
2248 SetLastError(0xdeadbeef);
2249 ret
= pIsWow64Process(GetCurrentProcess(), &is_wow64
);
2250 ok(ret
, "IsWow64Process error %lu\n", GetLastError());
2252 SetLastError(0xdeadbeef);
2253 machine
= native_machine
= 0xdead;
2254 ret
= pIsWow64Process2(GetCurrentProcess(), &machine
, &native_machine
);
2255 ok(ret
, "IsWow64Process2 error %lu\n", GetLastError());
2259 ok(machine
== IMAGE_FILE_MACHINE_I386
, "got %#x\n", machine
);
2260 ok(native_machine
== expect_native
, "got %#x\n", native_machine
);
2264 ok(machine
== IMAGE_FILE_MACHINE_UNKNOWN
, "got %#x\n", machine
);
2265 ok(native_machine
== expect_native
, "got %#x\n", native_machine
);
2268 SetLastError(0xdeadbeef);
2270 ret
= pIsWow64Process2(GetCurrentProcess(), &machine
, NULL
);
2271 ok(ret
, "IsWow64Process2 error %lu\n", GetLastError());
2273 ok(machine
== IMAGE_FILE_MACHINE_I386
, "got %#x\n", machine
);
2275 ok(machine
== IMAGE_FILE_MACHINE_UNKNOWN
, "got %#x\n", machine
);
2278 static void test_SystemInfo(void)
2280 SYSTEM_INFO si
, nsi
;
2282 USHORT machine
, native_machine
;
2284 if (!pGetNativeSystemInfo
)
2286 win_skip("GetNativeSystemInfo is not available\n");
2290 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
2293 pGetNativeSystemInfo(&nsi
);
2296 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
2298 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
2299 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2300 S(U(nsi
)).wProcessorArchitecture
);
2301 if (pIsWow64Process2
&& pIsWow64Process2(GetCurrentProcess(), &machine
, &native_machine
) &&
2302 native_machine
== IMAGE_FILE_MACHINE_ARM64
)
2304 ok(nsi
.dwProcessorType
== PROCESSOR_INTEL_PENTIUM
, "got %ld\n", nsi
.dwProcessorType
);
2305 ok(nsi
.wProcessorLevel
== 15, "got %d\n", nsi
.wProcessorLevel
);
2306 ok(nsi
.wProcessorRevision
== 0x40a, "got %d\n", nsi
.wProcessorRevision
);
2308 else ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
, "got %ld\n", nsi
.dwProcessorType
);
2313 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
2314 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2315 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
2316 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
2317 "Expected no difference for dwProcessorType, got %ld and %ld\n",
2318 si
.dwProcessorType
, nsi
.dwProcessorType
);
2322 static void test_ProcessorCount(void)
2324 DWORD active
, maximum
;
2326 if (!pGetActiveProcessorCount
|| !pGetMaximumProcessorCount
)
2328 win_skip("GetActiveProcessorCount or GetMaximumProcessorCount is not available\n");
2332 active
= pGetActiveProcessorCount(ALL_PROCESSOR_GROUPS
);
2333 maximum
= pGetMaximumProcessorCount(ALL_PROCESSOR_GROUPS
);
2334 ok(active
<= maximum
,
2335 "Number of active processors %li is greater than maximum number of processors %li\n",
2339 static void test_RegistryQuota(void)
2342 DWORD max_quota
, used_quota
;
2344 if (!pGetSystemRegistryQuota
)
2346 win_skip("GetSystemRegistryQuota is not available\n");
2350 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
2352 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2354 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
2356 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2358 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
2360 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2362 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
2364 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2367 static void test_TerminateProcess(void)
2369 static char cmdline
[] = "winver.exe";
2370 PROCESS_INFORMATION pi
;
2373 HANDLE dummy
, thread
;
2375 memset(&si
, 0, sizeof(si
));
2377 SetLastError(0xdeadbeef);
2378 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2379 ok(ret
, "CreateProcess error %lu\n", GetLastError());
2381 SetLastError(0xdeadbeef);
2382 thread
= CreateRemoteThread(pi
.hProcess
, NULL
, 0, (void *)0xdeadbeef, NULL
, CREATE_SUSPENDED
, &ret
);
2383 ok(thread
!= 0, "CreateRemoteThread error %ld\n", GetLastError());
2385 /* create a not closed thread handle duplicate in the target process */
2386 SetLastError(0xdeadbeef);
2387 ret
= DuplicateHandle(GetCurrentProcess(), thread
, pi
.hProcess
, &dummy
,
2388 0, FALSE
, DUPLICATE_SAME_ACCESS
);
2389 ok(ret
, "DuplicateHandle error %lu\n", GetLastError());
2391 SetLastError(0xdeadbeef);
2392 ret
= TerminateThread(thread
, 0);
2393 ok(ret
, "TerminateThread error %lu\n", GetLastError());
2394 CloseHandle(thread
);
2396 SetLastError(0xdeadbeef);
2397 ret
= TerminateProcess(pi
.hProcess
, 0);
2398 ok(ret
, "TerminateProcess error %lu\n", GetLastError());
2400 CloseHandle(pi
.hProcess
);
2401 CloseHandle(pi
.hThread
);
2404 static void test_DuplicateHandle(void)
2406 char path
[MAX_PATH
], file_name
[MAX_PATH
];
2407 HANDLE f
, fmin
, out
;
2411 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2412 GetCurrentProcess(), &out
, 0, FALSE
,
2413 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2414 ok(r
, "DuplicateHandle error %lu\n", GetLastError());
2415 r
= GetHandleInformation(out
, &info
);
2416 ok(r
, "GetHandleInformation error %lu\n", GetLastError());
2417 ok(info
== 0, "info = %lx\n", info
);
2418 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2421 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2422 GetCurrentProcess(), &out
, 0, TRUE
,
2423 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2424 ok(r
, "DuplicateHandle error %lu\n", GetLastError());
2425 r
= GetHandleInformation(out
, &info
);
2426 ok(r
, "GetHandleInformation error %lu\n", GetLastError());
2427 ok(info
== HANDLE_FLAG_INHERIT
, "info = %lx\n", info
);
2428 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2431 GetTempPathA(MAX_PATH
, path
);
2432 GetTempFileNameA(path
, "wt", 0, file_name
);
2433 f
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
2434 if (f
== INVALID_HANDLE_VALUE
)
2436 ok(0, "could not create %s\n", file_name
);
2440 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2441 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2442 ok(r
, "DuplicateHandle error %lu\n", GetLastError());
2443 ok(f
== out
, "f != out\n");
2444 r
= GetHandleInformation(out
, &info
);
2445 ok(r
, "GetHandleInformation error %lu\n", GetLastError());
2446 ok(info
== 0, "info = %lx\n", info
);
2448 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2449 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2450 ok(r
, "DuplicateHandle error %lu\n", GetLastError());
2451 ok(f
== out
, "f != out\n");
2452 r
= GetHandleInformation(out
, &info
);
2453 ok(r
, "GetHandleInformation error %lu\n", GetLastError());
2454 ok(info
== HANDLE_FLAG_INHERIT
, "info = %lx\n", info
);
2456 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, HANDLE_FLAG_PROTECT_FROM_CLOSE
);
2457 ok(r
, "SetHandleInformation error %lu\n", GetLastError());
2458 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2459 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2460 ok(r
, "DuplicateHandle error %lu\n", GetLastError());
2461 ok(f
!= out
, "f == out\n");
2462 r
= GetHandleInformation(out
, &info
);
2463 ok(r
, "GetHandleInformation error %lu\n", GetLastError());
2464 ok(info
== HANDLE_FLAG_INHERIT
, "info = %lx\n", info
);
2465 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, 0);
2466 ok(r
, "SetHandleInformation error %lu\n", GetLastError());
2468 /* Test if DuplicateHandle allocates first free handle */
2479 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2480 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2481 ok(r
, "DuplicateHandle error %lu\n", GetLastError());
2482 ok(f
== out
, "f != out\n");
2484 DeleteFileA(file_name
);
2486 f
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2487 ok(f
!= INVALID_HANDLE_VALUE
, "Failed to open CONIN$ %lu\n", GetLastError());
2488 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2489 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2490 ok(r
, "DuplicateHandle error %lu\n", GetLastError());
2491 ok(f
== out
|| broken(/* Win7 */ (((ULONG_PTR
)f
& 3) == 3) && (f
!= out
)), "f != out\n");
2495 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2496 static void _test_completion(int line
, HANDLE port
, DWORD ekey
, ULONG_PTR evalue
, ULONG_PTR eoverlapped
, DWORD wait
)
2498 LPOVERLAPPED overlapped
;
2503 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, wait
);
2505 ok_(__FILE__
, line
)(ret
, "GetQueuedCompletionStatus: %lx\n", GetLastError());
2508 ok_(__FILE__
, line
)(key
== ekey
, "unexpected key %lx\n", key
);
2509 ok_(__FILE__
, line
)(value
== evalue
, "unexpected value %p\n", (void *)value
);
2510 ok_(__FILE__
, line
)(overlapped
== (LPOVERLAPPED
)eoverlapped
, "unexpected overlapped %p\n", overlapped
);
2514 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2515 static void _create_process(int line
, const char *command
, LPPROCESS_INFORMATION pi
)
2518 char buffer
[MAX_PATH
+ 19];
2519 STARTUPINFOA si
= {0};
2521 sprintf(buffer
, "\"%s\" process %s", selfname
, command
);
2523 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, pi
);
2524 ok_(__FILE__
, line
)(ret
, "CreateProcess error %lu\n", GetLastError());
2528 static void test_IsProcessInJob(void)
2531 PROCESS_INFORMATION pi
;
2534 if (!pIsProcessInJob
)
2536 win_skip("IsProcessInJob not available.\n");
2540 job
= pCreateJobObjectW(NULL
, NULL
);
2541 ok(job
!= NULL
, "CreateJobObject error %lu\n", GetLastError());
2543 job2
= pCreateJobObjectW(NULL
, NULL
);
2544 ok(job2
!= NULL
, "CreateJobObject error %lu\n", GetLastError());
2546 create_process("wait", &pi
);
2549 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2550 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
2551 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2554 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2555 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
2556 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2558 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2559 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2562 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2563 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
2564 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2567 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2568 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
2569 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2572 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2573 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
2574 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2576 TerminateProcess(pi
.hProcess
, 0);
2577 wait_child_process(pi
.hProcess
);
2580 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2581 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
2582 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2584 CloseHandle(pi
.hProcess
);
2585 CloseHandle(pi
.hThread
);
2590 static void test_TerminateJobObject(void)
2593 PROCESS_INFORMATION pi
;
2597 job
= pCreateJobObjectW(NULL
, NULL
);
2598 ok(job
!= NULL
, "CreateJobObject error %lu\n", GetLastError());
2600 create_process("wait", &pi
);
2602 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2603 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2605 ret
= pTerminateJobObject(job
, 123);
2606 ok(ret
, "TerminateJobObject error %lu\n", GetLastError());
2608 /* not wait_child_process() because of the exit code */
2609 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2610 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %lu\n", dwret
);
2611 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2613 ret
= GetExitCodeProcess(pi
.hProcess
, &dwret
);
2614 ok(ret
, "GetExitCodeProcess error %lu\n", GetLastError());
2615 ok(dwret
== 123 || broken(dwret
== 0) /* randomly fails on Win 2000 / XP */,
2616 "wrong exitcode %lu\n", dwret
);
2618 CloseHandle(pi
.hProcess
);
2619 CloseHandle(pi
.hThread
);
2621 /* Test adding an already terminated process to a job object */
2622 create_process("exit", &pi
);
2623 wait_child_process(pi
.hProcess
);
2625 SetLastError(0xdeadbeef);
2626 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2627 ok(!ret
, "AssignProcessToJobObject unexpectedly succeeded\n");
2628 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2630 CloseHandle(pi
.hProcess
);
2631 CloseHandle(pi
.hThread
);
2636 static void test_QueryInformationJobObject(void)
2638 char buf
[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST
) + sizeof(ULONG_PTR
) * 4];
2639 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2640 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info
;
2641 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit_info
= &ext_limit_info
.BasicLimitInformation
;
2642 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting_info
;
2644 PROCESS_INFORMATION pi
[2];
2649 job
= pCreateJobObjectW(NULL
, NULL
);
2650 ok(job
!= NULL
, "CreateJobObject error %lu\n", GetLastError());
2652 /* Only active processes are returned */
2653 sprintf(buffer
, "sync kernel32-process-%lx", GetCurrentProcessId());
2654 sem
= CreateSemaphoreA(NULL
, 0, 1, buffer
+ 5);
2655 ok(sem
!= NULL
, "CreateSemaphoreA failed le=%lu\n", GetLastError());
2656 create_process(buffer
, &pi
[0]);
2658 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2659 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2661 ReleaseSemaphore(sem
, 1, NULL
);
2662 wait_and_close_child_process(&pi
[0]);
2664 create_process("wait", &pi
[0]);
2665 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2666 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2668 create_process("wait", &pi
[1]);
2669 ret
= pAssignProcessToJobObject(job
, pi
[1].hProcess
);
2670 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2672 SetLastError(0xdeadbeef);
2673 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2674 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
), &ret_len
);
2675 ok(!ret
, "QueryInformationJobObject expected failure\n");
2676 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2678 SetLastError(0xdeadbeef);
2679 memset(buf
, 0, sizeof(buf
));
2680 pid_list
->NumberOfAssignedProcesses
= 42;
2681 pid_list
->NumberOfProcessIdsInList
= 42;
2682 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2683 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[1]), &ret_len
);
2684 ok(!ret
, "QueryInformationJobObject expected failure\n");
2685 expect_eq_d(ERROR_MORE_DATA
, GetLastError());
2688 expect_eq_d(42, pid_list
->NumberOfAssignedProcesses
);
2689 expect_eq_d(42, pid_list
->NumberOfProcessIdsInList
);
2692 memset(buf
, 0, sizeof(buf
));
2693 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2694 ok(ret
, "QueryInformationJobObject error %lu\n", GetLastError());
2697 if (pid_list
->NumberOfAssignedProcesses
== 3) /* Win 8 */
2698 win_skip("Number of assigned processes broken on Win 8\n");
2701 ULONG_PTR
*list
= pid_list
->ProcessIdList
;
2703 ok(ret_len
== FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[2]),
2704 "QueryInformationJobObject returned ret_len=%lu\n", ret_len
);
2706 expect_eq_d(2, pid_list
->NumberOfAssignedProcesses
);
2707 expect_eq_d(2, pid_list
->NumberOfProcessIdsInList
);
2708 expect_eq_d(pi
[0].dwProcessId
, list
[0]);
2709 expect_eq_d(pi
[1].dwProcessId
, list
[1]);
2713 /* test JobObjectBasicLimitInformation */
2714 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2715 sizeof(*basic_limit_info
) - 1, &ret_len
);
2716 ok(!ret
, "QueryInformationJobObject expected failure\n");
2717 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2719 ret_len
= 0xdeadbeef;
2720 memset(basic_limit_info
, 0x11, sizeof(*basic_limit_info
));
2721 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2722 sizeof(*basic_limit_info
), &ret_len
);
2723 ok(ret
, "QueryInformationJobObject error %lu\n", GetLastError());
2724 ok(ret_len
== sizeof(*basic_limit_info
), "QueryInformationJobObject returned ret_len=%lu\n", ret_len
);
2725 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2727 /* test JobObjectExtendedLimitInformation */
2728 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2729 sizeof(ext_limit_info
) - 1, &ret_len
);
2730 ok(!ret
, "QueryInformationJobObject expected failure\n");
2731 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2733 ret_len
= 0xdeadbeef;
2734 memset(&ext_limit_info
, 0x11, sizeof(ext_limit_info
));
2735 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2736 sizeof(ext_limit_info
), &ret_len
);
2737 ok(ret
, "QueryInformationJobObject error %lu\n", GetLastError());
2738 ok(ret_len
== sizeof(ext_limit_info
), "QueryInformationJobObject returned ret_len=%lu\n", ret_len
);
2739 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2741 /* test JobObjectBasicAccountingInformation */
2742 ret
= pQueryInformationJobObject(job
, JobObjectBasicAccountingInformation
, &basic_accounting_info
,
2743 sizeof(basic_accounting_info
), &ret_len
);
2744 ok(ret
, "QueryInformationJobObject error %lu\n", GetLastError());
2745 ok(ret_len
== sizeof(basic_accounting_info
), "QueryInformationJobObject returned ret_len=%lu\n", ret_len
);
2746 expect_eq_d(3, basic_accounting_info
.TotalProcesses
);
2747 expect_eq_d(2, basic_accounting_info
.ActiveProcesses
);
2749 TerminateProcess(pi
[0].hProcess
, 0);
2750 CloseHandle(pi
[0].hProcess
);
2751 CloseHandle(pi
[0].hThread
);
2753 TerminateProcess(pi
[1].hProcess
, 0);
2754 CloseHandle(pi
[1].hProcess
);
2755 CloseHandle(pi
[1].hThread
);
2760 static void test_CompletionPort(void)
2762 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
2763 PROCESS_INFORMATION pi
, pi2
;
2767 job
= pCreateJobObjectW(NULL
, NULL
);
2768 ok(job
!= NULL
, "CreateJobObject error %lu\n", GetLastError());
2770 create_process("wait", &pi2
);
2771 ret
= pAssignProcessToJobObject(job
, pi2
.hProcess
);
2772 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2774 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
2775 ok(port
!= NULL
, "CreateIoCompletionPort error %lu\n", GetLastError());
2777 port_info
.CompletionKey
= job
;
2778 port_info
.CompletionPort
= port
;
2779 ret
= pSetInformationJobObject(job
, JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
2780 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
2782 create_process("wait", &pi
);
2784 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2785 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2787 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi2
.dwProcessId
, 0);
2788 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2790 TerminateProcess(pi
.hProcess
, 0);
2791 wait_child_process(pi
.hProcess
);
2793 test_completion(port
, JOB_OBJECT_MSG_EXIT_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2794 TerminateProcess(pi2
.hProcess
, 0);
2795 wait_child_process(pi2
.hProcess
);
2796 CloseHandle(pi2
.hProcess
);
2797 CloseHandle(pi2
.hThread
);
2799 test_completion(port
, JOB_OBJECT_MSG_EXIT_PROCESS
, (DWORD_PTR
)job
, pi2
.dwProcessId
, 0);
2800 test_completion(port
, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
, (DWORD_PTR
)job
, 0, 100);
2802 CloseHandle(pi
.hProcess
);
2803 CloseHandle(pi
.hThread
);
2808 static void test_KillOnJobClose(void)
2810 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2811 PROCESS_INFORMATION pi
;
2816 job
= pCreateJobObjectW(NULL
, NULL
);
2817 ok(job
!= NULL
, "CreateJobObject error %lu\n", GetLastError());
2819 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
;
2820 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2821 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
2823 win_skip("Kill on job close limit not available\n");
2826 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
2828 create_process("wait", &pi
);
2830 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2831 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2835 /* not wait_child_process() for the kill */
2836 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2837 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %lu\n", dwret
);
2838 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2840 CloseHandle(pi
.hProcess
);
2841 CloseHandle(pi
.hThread
);
2844 static void test_WaitForJobObject(void)
2848 PROCESS_INFORMATION pi
;
2852 /* test waiting for a job object when the process is killed */
2853 job
= pCreateJobObjectW(NULL
, NULL
);
2854 ok(job
!= NULL
, "CreateJobObject error %lu\n", GetLastError());
2856 dwret
= WaitForSingleObject(job
, 100);
2857 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %lu\n", dwret
);
2859 create_process("wait", &pi
);
2861 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2862 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2864 dwret
= WaitForSingleObject(job
, 100);
2865 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %lu\n", dwret
);
2867 ret
= pTerminateJobObject(job
, 123);
2868 ok(ret
, "TerminateJobObject error %lu\n", GetLastError());
2870 dwret
= WaitForSingleObject(job
, 500);
2871 ok(dwret
== WAIT_OBJECT_0
|| broken(dwret
== WAIT_TIMEOUT
),
2872 "WaitForSingleObject returned %lu\n", dwret
);
2874 if (dwret
== WAIT_TIMEOUT
) /* Win 2000/XP */
2876 CloseHandle(pi
.hProcess
);
2877 CloseHandle(pi
.hThread
);
2879 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2883 /* the object is not reset immediately */
2884 dwret
= WaitForSingleObject(job
, 100);
2885 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %lu\n", dwret
);
2887 CloseHandle(pi
.hProcess
);
2888 CloseHandle(pi
.hThread
);
2890 /* creating a new process doesn't reset the signalled state */
2891 create_process("wait", &pi
);
2893 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2894 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2896 dwret
= WaitForSingleObject(job
, 100);
2897 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %lu\n", dwret
);
2899 ret
= pTerminateJobObject(job
, 123);
2900 ok(ret
, "TerminateJobObject error %lu\n", GetLastError());
2902 CloseHandle(pi
.hProcess
);
2903 CloseHandle(pi
.hThread
);
2907 /* repeat the test, but this time the process terminates properly */
2908 job
= pCreateJobObjectW(NULL
, NULL
);
2909 ok(job
!= NULL
, "CreateJobObject error %lu\n", GetLastError());
2911 dwret
= WaitForSingleObject(job
, 100);
2912 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %lu\n", dwret
);
2914 sprintf(buffer
, "sync kernel32-process-%lx", GetCurrentProcessId());
2915 sem
= CreateSemaphoreA(NULL
, 0, 1, buffer
+ 5);
2916 ok(sem
!= NULL
, "CreateSemaphoreA failed le=%lu\n", GetLastError());
2917 create_process(buffer
, &pi
);
2919 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2920 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2921 ReleaseSemaphore(sem
, 1, NULL
);
2923 dwret
= WaitForSingleObject(job
, 100);
2924 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %lu\n", dwret
);
2926 wait_and_close_child_process(&pi
);
2931 static HANDLE
test_AddSelfToJob(void)
2936 job
= pCreateJobObjectW(NULL
, NULL
);
2937 ok(job
!= NULL
, "CreateJobObject error %lu\n", GetLastError());
2939 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
2940 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
2945 static void test_jobInheritance(HANDLE job
)
2947 PROCESS_INFORMATION pi
;
2950 if (!pIsProcessInJob
)
2952 win_skip("IsProcessInJob not available.\n");
2956 create_process("exit", &pi
);
2959 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2960 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
2961 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2963 wait_and_close_child_process(&pi
);
2966 static void test_BreakawayOk(HANDLE parent_job
)
2968 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2969 PROCESS_INFORMATION pi
;
2970 STARTUPINFOA si
= {0};
2971 char buffer
[MAX_PATH
+ 23];
2972 BOOL ret
, out
, nested_jobs
;
2975 if (!pIsProcessInJob
)
2977 win_skip("IsProcessInJob not available.\n");
2981 job
= pCreateJobObjectW(NULL
, NULL
);
2982 ok(!!job
, "CreateJobObjectW error %lu\n", GetLastError());
2984 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
2985 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
) /* before Win 8. */,
2986 "AssignProcessToJobObject error %lu\n", GetLastError());
2989 win_skip("Nested jobs are not supported.\n");
2991 sprintf(buffer
, "\"%s\" process exit", selfname
);
2992 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2993 ok(!ret
, "CreateProcessA expected failure\n");
2994 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2998 TerminateProcess(pi
.hProcess
, 0);
2999 wait_and_close_child_process(&pi
);
3004 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
3005 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
3006 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
3008 sprintf(buffer
, "\"%s\" process exit", selfname
);
3009 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
3010 ok(ret
, "CreateProcessA error %lu\n", GetLastError());
3012 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
3013 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
3014 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
3016 ret
= pIsProcessInJob(pi
.hProcess
, parent_job
, &out
);
3017 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
3018 ok(out
, "IsProcessInJob returned out=%u\n", out
);
3020 TerminateProcess(pi
.hProcess
, 0);
3021 wait_and_close_child_process(&pi
);
3024 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
3025 ret
= pSetInformationJobObject(parent_job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
3026 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
3028 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
3029 ok(ret
, "CreateProcessA error %lu\n", GetLastError());
3031 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
3032 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
3033 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
3035 ret
= pIsProcessInJob(pi
.hProcess
, parent_job
, &out
);
3036 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
3037 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
3039 wait_and_close_child_process(&pi
);
3041 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
3042 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
3043 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
3045 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
3046 ok(ret
, "CreateProcess error %lu\n", GetLastError());
3048 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
3049 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
3050 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
3052 wait_and_close_child_process(&pi
);
3054 /* unset breakaway ok */
3055 limit_info
.BasicLimitInformation
.LimitFlags
= 0;
3056 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
3057 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
3060 static void test_StartupNoConsole(void)
3063 char buffer
[2 * MAX_PATH
+ 25];
3064 STARTUPINFOA startup
;
3065 PROCESS_INFORMATION info
;
3067 memset(&startup
, 0, sizeof(startup
));
3068 startup
.cb
= sizeof(startup
);
3069 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3070 startup
.wShowWindow
= SW_SHOWNORMAL
;
3071 get_file_name(resfile
);
3072 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
3073 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
3074 &info
), "CreateProcess\n");
3075 wait_and_close_child_process(&info
);
3077 reload_child_info(resfile
);
3078 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
3079 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
3080 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
3081 okChildInt("TEB", "hStdInput", 0);
3082 okChildInt("TEB", "hStdOutput", 0);
3083 okChildInt("TEB", "hStdError", 0);
3085 DeleteFileA(resfile
);
3089 static void test_DetachConsoleHandles(void)
3092 char buffer
[2 * MAX_PATH
+ 25];
3093 STARTUPINFOA startup
;
3094 PROCESS_INFORMATION info
;
3097 memset(&startup
, 0, sizeof(startup
));
3098 startup
.cb
= sizeof(startup
);
3099 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
3100 startup
.wShowWindow
= SW_SHOWNORMAL
;
3101 startup
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
3102 startup
.hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
3103 startup
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
3104 get_file_name(resfile
);
3105 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
3106 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
3107 &info
), "CreateProcess\n");
3108 wait_and_close_child_process(&info
);
3110 reload_child_info(resfile
);
3111 result
= GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile
);
3112 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3113 result
= GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile
);
3114 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3115 result
= GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile
);
3116 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3117 result
= GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile
);
3118 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3119 result
= GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile
);
3120 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3121 result
= GetPrivateProfileIntA("TEB", "hStdError", 0, resfile
);
3122 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3125 DeleteFileA(resfile
);
3129 #if defined(__i386__) || defined(__x86_64__)
3130 static BOOL
read_nt_header(HANDLE process_handle
, MEMORY_BASIC_INFORMATION
*mbi
,
3131 IMAGE_NT_HEADERS
*nt_header
)
3133 IMAGE_DOS_HEADER dos_header
;
3135 if (!ReadProcessMemory(process_handle
, mbi
->BaseAddress
, &dos_header
, sizeof(dos_header
), NULL
))
3138 if ((dos_header
.e_magic
!= IMAGE_DOS_SIGNATURE
) ||
3139 ((ULONG
)dos_header
.e_lfanew
> mbi
->RegionSize
) ||
3140 (dos_header
.e_lfanew
< sizeof(dos_header
)))
3143 if (!ReadProcessMemory(process_handle
, (char *)mbi
->BaseAddress
+ dos_header
.e_lfanew
,
3144 nt_header
, sizeof(*nt_header
), NULL
))
3147 return (nt_header
->Signature
== IMAGE_NT_SIGNATURE
);
3150 static PVOID
get_process_exe(HANDLE process_handle
, IMAGE_NT_HEADERS
*nt_header
)
3152 PVOID exe_base
, address
;
3153 MEMORY_BASIC_INFORMATION mbi
;
3155 /* Find the EXE base in the new process */
3157 for (address
= NULL
;
3158 VirtualQueryEx(process_handle
, address
, &mbi
, sizeof(mbi
)) ;
3159 address
= (char *)mbi
.BaseAddress
+ mbi
.RegionSize
) {
3160 if ((mbi
.Type
== SEC_IMAGE
) &&
3161 read_nt_header(process_handle
, &mbi
, nt_header
) &&
3162 !(nt_header
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)) {
3163 exe_base
= mbi
.BaseAddress
;
3171 static BOOL
are_imports_resolved(HANDLE process_handle
, PVOID module_base
, IMAGE_NT_HEADERS
*nt_header
)
3174 IMAGE_IMPORT_DESCRIPTOR iid
;
3175 ULONG_PTR orig_iat_entry_value
, iat_entry_value
;
3177 ok(nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
, "Import table VA is zero\n");
3178 ok(nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].Size
, "Import table Size is zero\n");
3180 if (!nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
||
3181 !nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].Size
)
3184 /* Read the first IID */
3185 ret
= ReadProcessMemory(process_handle
,
3186 (char *)module_base
+ nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
,
3187 &iid
, sizeof(iid
), NULL
);
3188 ok(ret
, "Failed to read remote module IID (%ld)\n", GetLastError());
3190 /* Validate the IID is present and not a bound import, and that we have
3191 an OriginalFirstThunk to compare with */
3192 ok(iid
.Name
, "Module first IID does not have a Name\n");
3193 ok(iid
.FirstThunk
, "Module first IID does not have a FirstThunk\n");
3194 ok(!iid
.TimeDateStamp
, "Module first IID is a bound import (UNSUPPORTED for current test)\n");
3195 ok(iid
.OriginalFirstThunk
, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3197 /* Read a single IAT entry from the FirstThunk */
3198 ret
= ReadProcessMemory(process_handle
, (char *)module_base
+ iid
.FirstThunk
,
3199 &iat_entry_value
, sizeof(iat_entry_value
), NULL
);
3200 ok(ret
, "Failed to read IAT entry from FirstThunk (%ld)\n", GetLastError());
3201 ok(iat_entry_value
, "IAT entry in FirstThunk is NULL\n");
3203 /* Read a single IAT entry from the OriginalFirstThunk */
3204 ret
= ReadProcessMemory(process_handle
, (char *)module_base
+ iid
.OriginalFirstThunk
,
3205 &orig_iat_entry_value
, sizeof(orig_iat_entry_value
), NULL
);
3206 ok(ret
, "Failed to read IAT entry from OriginalFirstThunk (%ld)\n", GetLastError());
3207 ok(orig_iat_entry_value
, "IAT entry in OriginalFirstThunk is NULL\n");
3209 return iat_entry_value
!= orig_iat_entry_value
;
3212 static void test_SuspendProcessNewThread(void)
3215 STARTUPINFOA si
= {0};
3216 PROCESS_INFORMATION pi
= {0};
3217 PVOID exe_base
, exit_thread_ptr
;
3218 IMAGE_NT_HEADERS nt_header
;
3219 HANDLE thread_handle
= NULL
;
3220 DWORD dret
, exit_code
= 0;
3223 exit_thread_ptr
= GetProcAddress(hkernel32
, "ExitThread");
3224 ok(exit_thread_ptr
!= NULL
, "GetProcAddress ExitThread failed\n");
3227 ret
= CreateProcessA(NULL
, selfname
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
3228 ok(ret
, "Failed to create process (%ld)\n", GetLastError());
3230 exe_base
= get_process_exe(pi
.hProcess
, &nt_header
);
3231 ok(exe_base
!= NULL
, "Could not find EXE in remote process\n");
3233 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3234 ok(!ret
, "IAT entry resolved prematurely\n");
3236 thread_handle
= CreateRemoteThread(pi
.hProcess
, NULL
, 0,
3237 (LPTHREAD_START_ROUTINE
)exit_thread_ptr
,
3238 (PVOID
)(ULONG_PTR
)0x1234, CREATE_SUSPENDED
, NULL
);
3239 ok(thread_handle
!= NULL
, "Could not create remote thread (%ld)\n", GetLastError());
3241 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3242 ok(!ret
, "IAT entry resolved prematurely\n");
3244 ctx
.ContextFlags
= CONTEXT_ALL
;
3245 ret
= GetThreadContext( thread_handle
, &ctx
);
3246 ok( ret
, "Failed retrieving remote thread context (%ld)\n", GetLastError() );
3247 ok( ctx
.ContextFlags
== CONTEXT_ALL
, "wrong flags %lx\n", ctx
.ContextFlags
);
3249 ok( !ctx
.Rax
, "rax is not zero %Ix\n", ctx
.Rax
);
3250 ok( !ctx
.Rbx
, "rbx is not zero %Ix\n", ctx
.Rbx
);
3251 ok( ctx
.Rcx
== (ULONG_PTR
)exit_thread_ptr
, "wrong rcx %Ix/%p\n", ctx
.Rcx
, exit_thread_ptr
);
3252 ok( ctx
.Rdx
== 0x1234, "wrong rdx %Ix\n", ctx
.Rdx
);
3253 ok( !ctx
.Rsi
, "rsi is not zero %Ix\n", ctx
.Rsi
);
3254 ok( !ctx
.Rdi
, "rdi is not zero %Ix\n", ctx
.Rdi
);
3255 ok( !ctx
.Rbp
, "rbp is not zero %Ix\n", ctx
.Rbp
);
3256 ok( !ctx
.R8
, "r8 is not zero %Ix\n", ctx
.R8
);
3257 ok( !ctx
.R9
, "r9 is not zero %Ix\n", ctx
.R9
);
3258 ok( !ctx
.R10
, "r10 is not zero %Ix\n", ctx
.R10
);
3259 ok( !ctx
.R11
, "r11 is not zero %Ix\n", ctx
.R11
);
3260 ok( !ctx
.R12
, "r12 is not zero %Ix\n", ctx
.R12
);
3261 ok( !ctx
.R13
, "r13 is not zero %Ix\n", ctx
.R13
);
3262 ok( !ctx
.R14
, "r14 is not zero %Ix\n", ctx
.R14
);
3263 ok( !ctx
.R15
, "r15 is not zero %Ix\n", ctx
.R15
);
3264 ok( !((ctx
.Rsp
+ 0x28) & 0xfff), "rsp is not at top of stack page %Ix\n", ctx
.Rsp
);
3265 ok( ctx
.EFlags
== 0x200, "wrong flags %08lx\n", ctx
.EFlags
);
3266 ok( ctx
.MxCsr
== 0x1f80, "wrong mxcsr %08lx\n", ctx
.MxCsr
);
3267 ok( ctx
.FltSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FltSave
.ControlWord
);
3269 ok( !ctx
.Ebp
|| broken(ctx
.Ebp
), /* winxp */ "ebp is not zero %08lx\n", ctx
.Ebp
);
3270 if (!ctx
.Ebp
) /* winxp is completely different */
3272 ok( !ctx
.Ecx
, "ecx is not zero %08lx\n", ctx
.Ecx
);
3273 ok( !ctx
.Edx
, "edx is not zero %08lx\n", ctx
.Edx
);
3274 ok( !ctx
.Esi
, "esi is not zero %08lx\n", ctx
.Esi
);
3275 ok( !ctx
.Edi
, "edi is not zero %08lx\n", ctx
.Edi
);
3277 ok( ctx
.Eax
== (ULONG_PTR
)exit_thread_ptr
, "wrong eax %08lx/%p\n", ctx
.Eax
, exit_thread_ptr
);
3278 ok( ctx
.Ebx
== 0x1234, "wrong ebx %08lx\n", ctx
.Ebx
);
3279 ok( !((ctx
.Esp
+ 0x10) & 0xfff) || broken( !((ctx
.Esp
+ 4) & 0xfff) ), /* winxp, w2k3 */
3280 "esp is not at top of stack page or properly aligned: %08lx\n", ctx
.Esp
);
3281 ok( (ctx
.EFlags
& ~2) == 0x200, "wrong flags %08lx\n", ctx
.EFlags
);
3282 ok( (WORD
)ctx
.FloatSave
.ControlWord
== 0x27f, "wrong control %08lx\n", ctx
.FloatSave
.ControlWord
);
3283 ok( *(WORD
*)ctx
.ExtendedRegisters
== 0x27f, "wrong control %08x\n", *(WORD
*)ctx
.ExtendedRegisters
);
3286 ResumeThread( thread_handle
);
3287 dret
= WaitForSingleObject(thread_handle
, 60000);
3288 ok(dret
== WAIT_OBJECT_0
, "Waiting for remote thread failed (%ld)\n", GetLastError());
3289 ret
= GetExitCodeThread(thread_handle
, &exit_code
);
3290 ok(ret
, "Failed to retrieve remote thread exit code (%ld)\n", GetLastError());
3291 ok(exit_code
== 0x1234, "Invalid remote thread exit code\n");
3293 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3294 ok(ret
, "EXE IAT entry not resolved\n");
3297 CloseHandle(thread_handle
);
3299 /* Note that the child's main thread is still suspended so the exit code
3300 * is set by the TerminateProcess() call.
3302 TerminateProcess(pi
.hProcess
, 0);
3303 wait_and_close_child_process(&pi
);
3306 static void test_SuspendProcessState(void)
3310 ULONG pipe_write_buf
;
3311 ULONG pipe_read_buf
;
3312 ULONG bytes_returned
;
3313 CHAR pipe_name
[MAX_PATH
];
3317 struct remote_rop_chain
3319 void *exit_process_ptr
;
3324 ULONG_PTR pipe_read_buf_size
;
3325 ULONG_PTR bytes_returned
;
3329 struct remote_rop_chain
3331 void *exit_process_ptr
;
3332 ULONG_PTR pipe_name
;
3333 ULONG_PTR pipe_write_buf
;
3334 ULONG_PTR pipe_write_buf_size
;
3335 ULONG_PTR pipe_read_buf
;
3336 ULONG_PTR pipe_read_buf_size
;
3337 ULONG_PTR bytes_returned
;
3339 void *unreached_ret
;
3340 ULONG_PTR exit_code
;
3344 static const char pipe_name
[] = "\\\\.\\pipe\\TestPipe";
3345 static const ULONG pipe_write_magic
= 0x454e4957;
3346 STARTUPINFOA si
= {0};
3347 PROCESS_INFORMATION pi
= {0};
3348 PVOID exe_base
, remote_pipe_params
, exit_process_ptr
,
3350 IMAGE_NT_HEADERS nt_header
;
3351 struct pipe_params pipe_params
;
3352 struct remote_rop_chain rop_chain
;
3354 HANDLE server_pipe_handle
;
3355 BOOL pipe_connected
;
3356 ULONG pipe_magic
, numb
;
3358 void *user_thread_start
, *start_ptr
, *entry_ptr
, *peb_ptr
;
3359 PEB child_peb
, *peb
= NtCurrentTeb()->Peb
;
3361 exit_process_ptr
= GetProcAddress(hkernel32
, "ExitProcess");
3362 ok(exit_process_ptr
!= NULL
, "GetProcAddress ExitProcess failed\n");
3364 call_named_pipe_a
= GetProcAddress(hkernel32
, "CallNamedPipeA");
3365 ok(call_named_pipe_a
!= NULL
, "GetProcAddress CallNamedPipeA failed\n");
3368 ret
= CreateProcessA(NULL
, selfname
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
3369 ok(ret
, "Failed to create process (%ld)\n", GetLastError());
3371 exe_base
= get_process_exe(pi
.hProcess
, &nt_header
);
3372 /* Make sure we found the EXE in the new process */
3373 ok(exe_base
!= NULL
, "Could not find EXE in remote process\n");
3375 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3376 ok(!ret
, "IAT entry resolved prematurely\n");
3378 server_pipe_handle
= CreateNamedPipeA(pipe_name
, PIPE_ACCESS_DUPLEX
| FILE_FLAG_WRITE_THROUGH
,
3379 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
, 1, 0x20000, 0x20000,
3381 ok(server_pipe_handle
!= INVALID_HANDLE_VALUE
, "Failed to create communication pipe (%ld)\n", GetLastError());
3383 /* Set up the remote process environment */
3384 ctx
.ContextFlags
= CONTEXT_ALL
;
3385 ret
= GetThreadContext(pi
.hThread
, &ctx
);
3386 ok(ret
, "Failed retrieving remote thread context (%ld)\n", GetLastError());
3387 ok( ctx
.ContextFlags
== CONTEXT_ALL
, "wrong flags %lx\n", ctx
.ContextFlags
);
3389 remote_pipe_params
= VirtualAllocEx(pi
.hProcess
, NULL
, sizeof(pipe_params
), MEM_COMMIT
, PAGE_READWRITE
);
3390 ok(remote_pipe_params
!= NULL
, "Failed allocating memory in remote process (%ld)\n", GetLastError());
3392 pipe_params
.pipe_write_buf
= pipe_write_magic
;
3393 pipe_params
.pipe_read_buf
= 0;
3394 pipe_params
.bytes_returned
= 0;
3395 strcpy(pipe_params
.pipe_name
, pipe_name
);
3397 ret
= WriteProcessMemory(pi
.hProcess
, remote_pipe_params
,
3398 &pipe_params
, sizeof(pipe_params
), NULL
);
3399 ok(ret
, "Failed to write to remote process memory (%ld)\n", GetLastError());
3402 ok( !ctx
.Rax
, "rax is not zero %Ix\n", ctx
.Rax
);
3403 ok( !ctx
.Rbx
, "rbx is not zero %Ix\n", ctx
.Rbx
);
3404 ok( !ctx
.Rsi
, "rsi is not zero %Ix\n", ctx
.Rsi
);
3405 ok( !ctx
.Rdi
, "rdi is not zero %Ix\n", ctx
.Rdi
);
3406 ok( !ctx
.Rbp
, "rbp is not zero %Ix\n", ctx
.Rbp
);
3407 ok( !ctx
.R8
, "r8 is not zero %Ix\n", ctx
.R8
);
3408 ok( !ctx
.R9
, "r9 is not zero %Ix\n", ctx
.R9
);
3409 ok( !ctx
.R10
, "r10 is not zero %Ix\n", ctx
.R10
);
3410 ok( !ctx
.R11
, "r11 is not zero %Ix\n", ctx
.R11
);
3411 ok( !ctx
.R12
, "r12 is not zero %Ix\n", ctx
.R12
);
3412 ok( !ctx
.R13
, "r13 is not zero %Ix\n", ctx
.R13
);
3413 ok( !ctx
.R14
, "r14 is not zero %Ix\n", ctx
.R14
);
3414 ok( !ctx
.R15
, "r15 is not zero %Ix\n", ctx
.R15
);
3415 ok( !((ctx
.Rsp
+ 0x28) & 0xfff), "rsp is not at top of stack page %Ix\n", ctx
.Rsp
);
3416 ok( ctx
.EFlags
== 0x200, "wrong flags %08lx\n", ctx
.EFlags
);
3417 ok( ctx
.MxCsr
== 0x1f80, "wrong mxcsr %08lx\n", ctx
.MxCsr
);
3418 ok( ctx
.FltSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FltSave
.ControlWord
);
3419 start_ptr
= (void *)ctx
.Rip
;
3420 entry_ptr
= (void *)ctx
.Rcx
;
3421 peb_ptr
= (void *)ctx
.Rdx
;
3423 rop_chain
.exit_process_ptr
= exit_process_ptr
;
3424 ctx
.Rcx
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_name
);
3425 ctx
.Rdx
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_write_buf
);
3426 ctx
.R8
= sizeof(pipe_params
.pipe_write_buf
);
3427 ctx
.R9
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_read_buf
);
3428 rop_chain
.pipe_read_buf_size
= sizeof(pipe_params
.pipe_read_buf
);
3429 rop_chain
.bytes_returned
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, bytes_returned
);
3430 rop_chain
.timeout
= 10000;
3432 ctx
.Rip
= (ULONG_PTR
)call_named_pipe_a
;
3433 ctx
.Rsp
-= sizeof(rop_chain
);
3434 ret
= WriteProcessMemory(pi
.hProcess
, (void *)ctx
.Rsp
, &rop_chain
, sizeof(rop_chain
), NULL
);
3435 ok(ret
, "Failed to write to remote process thread stack (%ld)\n", GetLastError());
3437 ok( !ctx
.Ebp
|| broken(ctx
.Ebp
), /* winxp */ "ebp is not zero %08lx\n", ctx
.Ebp
);
3438 if (!ctx
.Ebp
) /* winxp is completely different */
3440 ok( !ctx
.Ecx
, "ecx is not zero %08lx\n", ctx
.Ecx
);
3441 ok( !ctx
.Edx
, "edx is not zero %08lx\n", ctx
.Edx
);
3442 ok( !ctx
.Esi
, "esi is not zero %08lx\n", ctx
.Esi
);
3443 ok( !ctx
.Edi
, "edi is not zero %08lx\n", ctx
.Edi
);
3445 ok( !((ctx
.Esp
+ 0x10) & 0xfff) || broken( !((ctx
.Esp
+ 4) & 0xfff) ), /* winxp, w2k3 */
3446 "esp is not at top of stack page or properly aligned: %08lx\n", ctx
.Esp
);
3447 ok( (ctx
.EFlags
& ~2) == 0x200, "wrong flags %08lx\n", ctx
.EFlags
);
3448 ok( (WORD
)ctx
.FloatSave
.ControlWord
== 0x27f, "wrong control %08lx\n", ctx
.FloatSave
.ControlWord
);
3449 ok( *(WORD
*)ctx
.ExtendedRegisters
== 0x27f, "wrong control %08x\n", *(WORD
*)ctx
.ExtendedRegisters
);
3450 start_ptr
= (void *)ctx
.Eip
;
3451 entry_ptr
= (void *)ctx
.Eax
;
3452 peb_ptr
= (void *)ctx
.Ebx
;
3454 rop_chain
.exit_process_ptr
= exit_process_ptr
;
3455 rop_chain
.pipe_name
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_name
);
3456 rop_chain
.pipe_write_buf
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_write_buf
);
3457 rop_chain
.pipe_write_buf_size
= sizeof(pipe_params
.pipe_write_buf
);
3458 rop_chain
.pipe_read_buf
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_read_buf
);
3459 rop_chain
.pipe_read_buf_size
= sizeof(pipe_params
.pipe_read_buf
);
3460 rop_chain
.bytes_returned
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, bytes_returned
);
3461 rop_chain
.timeout
= 10000;
3462 rop_chain
.exit_code
= 0;
3464 ctx
.Eip
= (ULONG_PTR
)call_named_pipe_a
;
3465 ctx
.Esp
-= sizeof(rop_chain
);
3466 ret
= WriteProcessMemory(pi
.hProcess
, (void *)ctx
.Esp
, &rop_chain
, sizeof(rop_chain
), NULL
);
3467 ok(ret
, "Failed to write to remote process thread stack (%ld)\n", GetLastError());
3470 ret
= ReadProcessMemory( pi
.hProcess
, peb_ptr
, &child_peb
, sizeof(child_peb
), NULL
);
3471 ok( ret
, "Failed to read PEB (%lu)\n", GetLastError() );
3472 ok( child_peb
.ImageBaseAddress
== exe_base
, "wrong base %p/%p\n",
3473 child_peb
.ImageBaseAddress
, exe_base
);
3474 user_thread_start
= GetProcAddress( GetModuleHandleA("ntdll.dll"), "RtlUserThreadStart" );
3475 if (user_thread_start
)
3476 ok( start_ptr
== user_thread_start
,
3477 "wrong start addr %p / %p\n", start_ptr
, user_thread_start
);
3478 ok( entry_ptr
== (char *)exe_base
+ nt_header
.OptionalHeader
.AddressOfEntryPoint
,
3479 "wrong entry point %p/%p\n", entry_ptr
,
3480 (char *)exe_base
+ nt_header
.OptionalHeader
.AddressOfEntryPoint
);
3482 ok( !child_peb
.LdrData
, "LdrData set %p\n", child_peb
.LdrData
);
3483 ok( !child_peb
.FastPebLock
, "FastPebLock set %p\n", child_peb
.FastPebLock
);
3484 ok( !child_peb
.TlsBitmap
, "TlsBitmap set %p\n", child_peb
.TlsBitmap
);
3485 ok( !child_peb
.TlsExpansionBitmap
, "TlsExpansionBitmap set %p\n", child_peb
.TlsExpansionBitmap
);
3486 ok( !child_peb
.LoaderLock
, "LoaderLock set %p\n", child_peb
.LoaderLock
);
3487 ok( !child_peb
.ProcessHeap
, "ProcessHeap set %p\n", child_peb
.ProcessHeap
);
3488 ok( !child_peb
.CSDVersion
.Buffer
, "CSDVersion set %s\n", debugstr_w(child_peb
.CSDVersion
.Buffer
) );
3490 ok( child_peb
.OSMajorVersion
== peb
->OSMajorVersion
, "OSMajorVersion not set %lu\n", child_peb
.OSMajorVersion
);
3491 ok( child_peb
.OSPlatformId
== peb
->OSPlatformId
, "OSPlatformId not set %lu\n", child_peb
.OSPlatformId
);
3492 ok( child_peb
.SessionId
== peb
->SessionId
, "SessionId not set %lu\n", child_peb
.SessionId
);
3493 ok( child_peb
.CriticalSectionTimeout
.QuadPart
, "CriticalSectionTimeout not set %s\n",
3494 wine_dbgstr_longlong(child_peb
.CriticalSectionTimeout
.QuadPart
) );
3495 ok( child_peb
.HeapSegmentReserve
== peb
->HeapSegmentReserve
,
3496 "HeapSegmentReserve not set %Iu\n", child_peb
.HeapSegmentReserve
);
3497 ok( child_peb
.HeapSegmentCommit
== peb
->HeapSegmentCommit
,
3498 "HeapSegmentCommit not set %Iu\n", child_peb
.HeapSegmentCommit
);
3499 ok( child_peb
.HeapDeCommitTotalFreeThreshold
== peb
->HeapDeCommitTotalFreeThreshold
,
3500 "HeapDeCommitTotalFreeThreshold not set %Iu\n", child_peb
.HeapDeCommitTotalFreeThreshold
);
3501 ok( child_peb
.HeapDeCommitFreeBlockThreshold
== peb
->HeapDeCommitFreeBlockThreshold
,
3502 "HeapDeCommitFreeBlockThreshold not set %Iu\n", child_peb
.HeapDeCommitFreeBlockThreshold
);
3504 if (pNtQueryInformationThread
)
3507 THREAD_BASIC_INFORMATION info
;
3508 NTSTATUS status
= pNtQueryInformationThread( pi
.hThread
, ThreadBasicInformation
,
3509 &info
, sizeof(info
), NULL
);
3510 ok( !status
, "NtQueryInformationProcess failed %lx\n", status
);
3511 ret
= ReadProcessMemory( pi
.hProcess
, info
.TebBaseAddress
, &child_teb
, sizeof(child_teb
), NULL
);
3512 ok( ret
, "Failed to read TEB (%lu)\n", GetLastError() );
3514 ok( child_teb
.Peb
== peb_ptr
, "wrong Peb %p / %p\n", child_teb
.Peb
, peb_ptr
);
3515 ok( PtrToUlong(child_teb
.ClientId
.UniqueProcess
) == pi
.dwProcessId
, "wrong pid %lx / %lx\n",
3516 PtrToUlong(child_teb
.ClientId
.UniqueProcess
), pi
.dwProcessId
);
3517 ok( PtrToUlong(child_teb
.ClientId
.UniqueThread
) == pi
.dwThreadId
, "wrong tid %lx / %lx\n",
3518 PtrToUlong(child_teb
.ClientId
.UniqueThread
), pi
.dwThreadId
);
3519 ok( PtrToUlong(child_teb
.RealClientId
.UniqueProcess
) == pi
.dwProcessId
, "wrong real pid %lx / %lx\n",
3520 PtrToUlong(child_teb
.RealClientId
.UniqueProcess
), pi
.dwProcessId
);
3521 ok( PtrToUlong(child_teb
.RealClientId
.UniqueThread
) == pi
.dwThreadId
, "wrong real tid %lx / %lx\n",
3522 PtrToUlong(child_teb
.RealClientId
.UniqueThread
), pi
.dwThreadId
);
3523 ok( child_teb
.StaticUnicodeString
.MaximumLength
== sizeof(child_teb
.StaticUnicodeBuffer
),
3524 "StaticUnicodeString.MaximumLength wrong %x\n", child_teb
.StaticUnicodeString
.MaximumLength
);
3525 ok( (char *)child_teb
.StaticUnicodeString
.Buffer
== (char *)info
.TebBaseAddress
+ offsetof(TEB
, StaticUnicodeBuffer
),
3526 "StaticUnicodeString.Buffer wrong %p\n", child_teb
.StaticUnicodeString
.Buffer
);
3528 ok( !child_teb
.CurrentLocale
, "CurrentLocale set %lx\n", child_teb
.CurrentLocale
);
3529 ok( !child_teb
.TlsLinks
.Flink
, "TlsLinks.Flink set %p\n", child_teb
.TlsLinks
.Flink
);
3530 ok( !child_teb
.TlsLinks
.Blink
, "TlsLinks.Blink set %p\n", child_teb
.TlsLinks
.Blink
);
3531 ok( !child_teb
.TlsExpansionSlots
, "TlsExpansionSlots set %p\n", child_teb
.TlsExpansionSlots
);
3532 ok( !child_teb
.FlsSlots
, "FlsSlots set %p\n", child_teb
.FlsSlots
);
3535 ret
= SetThreadContext(pi
.hThread
, &ctx
);
3536 ok(ret
, "Failed to set remote thread context (%ld)\n", GetLastError());
3538 ResumeThread(pi
.hThread
);
3540 pipe_connected
= ConnectNamedPipe(server_pipe_handle
, NULL
) || (GetLastError() == ERROR_PIPE_CONNECTED
);
3541 ok(pipe_connected
, "Pipe did not connect\n");
3543 ret
= ReadFile(server_pipe_handle
, &pipe_magic
, sizeof(pipe_magic
), &numb
, NULL
);
3544 ok(ret
, "Failed to read buffer from pipe (%ld)\n", GetLastError());
3546 ok(pipe_magic
== pipe_write_magic
, "Did not get the correct magic from the remote process\n");
3548 /* Validate the imports: at this point the thread in the new process
3549 * should have initialized the EXE module imports and called each dll's
3550 * DllMain(), notifying it of the new thread in the process.
3552 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3553 ok(ret
, "EXE IAT is not resolved\n");
3555 ret
= WriteFile(server_pipe_handle
, &pipe_magic
, sizeof(pipe_magic
), &numb
, NULL
);
3556 ok(ret
, "Failed to write the magic back to the pipe (%ld)\n", GetLastError());
3557 CloseHandle(server_pipe_handle
);
3559 /* Avoid wait_child_process() because the exit code results from a race
3560 * between the TerminateProcess() call and the child's ExitProcess() call
3561 * which uses a random value in the 64 bit case.
3563 TerminateProcess(pi
.hProcess
, 0);
3564 WaitForSingleObject(pi
.hProcess
, 10000);
3565 CloseHandle(pi
.hProcess
);
3566 CloseHandle(pi
.hThread
);
3569 static void test_SuspendProcessNewThread(void)
3572 static void test_SuspendProcessState(void)
3577 static void test_DetachStdHandles(void)
3580 char buffer
[2 * MAX_PATH
+ 25], tempfile
[MAX_PATH
];
3581 STARTUPINFOA startup
;
3582 PROCESS_INFORMATION info
;
3583 HANDLE hstdin
, hstdout
, hstderr
, htemp
;
3586 hstdin
= GetStdHandle(STD_INPUT_HANDLE
);
3587 hstdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
3588 hstderr
= GetStdHandle(STD_ERROR_HANDLE
);
3590 get_file_name(tempfile
);
3591 htemp
= CreateFileA(tempfile
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
3592 ok(htemp
!= INVALID_HANDLE_VALUE
, "failed opening temporary file\n");
3594 memset(&startup
, 0, sizeof(startup
));
3595 startup
.cb
= sizeof(startup
);
3596 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3597 startup
.wShowWindow
= SW_SHOWNORMAL
;
3598 get_file_name(resfile
);
3599 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, resfile
);
3601 SetStdHandle(STD_INPUT_HANDLE
, htemp
);
3602 SetStdHandle(STD_OUTPUT_HANDLE
, htemp
);
3603 SetStdHandle(STD_ERROR_HANDLE
, htemp
);
3605 res
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
3608 SetStdHandle(STD_INPUT_HANDLE
, hstdin
);
3609 SetStdHandle(STD_OUTPUT_HANDLE
, hstdout
);
3610 SetStdHandle(STD_ERROR_HANDLE
, hstderr
);
3612 ok(res
, "CreateProcess failed\n");
3613 wait_and_close_child_process(&info
);
3615 reload_child_info(resfile
);
3616 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
3617 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
3618 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
3619 okChildInt("TEB", "hStdInput", 0);
3620 okChildInt("TEB", "hStdOutput", 0);
3621 okChildInt("TEB", "hStdError", 0);
3623 DeleteFileA(resfile
);
3626 DeleteFileA(tempfile
);
3630 static void test_GetNumaProcessorNode(void)
3637 if (!pGetNumaProcessorNode
)
3639 win_skip("GetNumaProcessorNode is missing\n");
3644 for (i
= 0; i
< 256; i
++)
3646 SetLastError(0xdeadbeef);
3647 node
= (i
< si
.dwNumberOfProcessors
) ? 0xFF : 0xAA;
3648 ret
= pGetNumaProcessorNode(i
, &node
);
3649 if (i
< si
.dwNumberOfProcessors
)
3651 ok(ret
, "GetNumaProcessorNode returned FALSE for processor %d\n", i
);
3652 ok(node
!= 0xFF, "expected node != 0xFF, but got 0xFF\n");
3656 ok(!ret
, "GetNumaProcessorNode returned TRUE for processor %d\n", i
);
3657 ok(node
== 0xFF || broken(node
== 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node
);
3658 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
3663 static void test_session_info(void)
3665 DWORD session_id
, active_session
;
3668 r
= ProcessIdToSessionId(GetCurrentProcessId(), &session_id
);
3669 ok(r
, "ProcessIdToSessionId failed: %lu\n", GetLastError());
3670 trace("session_id = %lx\n", session_id
);
3672 active_session
= pWTSGetActiveConsoleSessionId();
3673 trace("active_session = %lx\n", active_session
);
3676 static void test_process_info(HANDLE hproc
)
3679 static const ULONG info_size
[] =
3681 sizeof(PROCESS_BASIC_INFORMATION
) /* ProcessBasicInformation */,
3682 sizeof(QUOTA_LIMITS
) /* ProcessQuotaLimits */,
3683 sizeof(IO_COUNTERS
) /* ProcessIoCounters */,
3684 sizeof(VM_COUNTERS
) /* ProcessVmCounters */,
3685 sizeof(KERNEL_USER_TIMES
) /* ProcessTimes */,
3686 sizeof(ULONG
) /* ProcessBasePriority */,
3687 sizeof(ULONG
) /* ProcessRaisePriority */,
3688 sizeof(HANDLE
) /* ProcessDebugPort */,
3689 sizeof(HANDLE
) /* ProcessExceptionPort */,
3690 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3691 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3692 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3693 sizeof(ULONG
) /* ProcessDefaultHardErrorMode */,
3694 0 /* ProcessIoPortHandlers: kernel-mode only */,
3695 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3696 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3697 sizeof(ULONG
) /* ProcessUserModeIOPL */,
3698 sizeof(BOOLEAN
) /* ProcessEnableAlignmentFaultFixup */,
3699 sizeof(PROCESS_PRIORITY_CLASS
) /* ProcessPriorityClass */,
3700 sizeof(ULONG
) /* ProcessWx86Information */,
3701 sizeof(ULONG
) /* ProcessHandleCount */,
3702 sizeof(ULONG_PTR
) /* ProcessAffinityMask */,
3703 sizeof(ULONG
) /* ProcessPriorityBoost */,
3704 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3705 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3706 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3707 sizeof(ULONG_PTR
) /* ProcessWow64Information */,
3708 sizeof(buf
) /* ProcessImageFileName */,
3709 sizeof(ULONG
) /* ProcessLUIDDeviceMapsEnabled */,
3710 sizeof(ULONG
) /* ProcessBreakOnTermination */,
3711 sizeof(HANDLE
) /* ProcessDebugObjectHandle */,
3712 sizeof(ULONG
) /* ProcessDebugFlags */,
3713 sizeof(buf
) /* ProcessHandleTracing */,
3714 sizeof(ULONG
) /* ProcessIoPriority */,
3715 sizeof(ULONG
) /* ProcessExecuteFlags */,
3716 0 /* FIXME: sizeof(?) ProcessTlsInformation */,
3717 sizeof(ULONG
) /* ProcessCookie */,
3718 sizeof(SECTION_IMAGE_INFORMATION
) /* ProcessImageInformation */,
3719 sizeof(PROCESS_CYCLE_TIME_INFORMATION
) /* ProcessCycleTime */,
3720 sizeof(ULONG
) /* ProcessPagePriority */,
3721 40 /* ProcessInstrumentationCallback */,
3722 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
3723 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
3724 sizeof(buf
) /* ProcessImageFileNameWin32 */,
3725 #if 0 /* FIXME: Add remaining classes */
3726 sizeof(HANDLE
) /* ProcessImageFileMapping */,
3727 sizeof(PROCESS_AFFINITY_UPDATE_MODE
) /* ProcessAffinityUpdateMode */,
3728 sizeof(PROCESS_MEMORY_ALLOCATION_MODE
) /* ProcessMemoryAllocationMode */,
3729 sizeof(USHORT
[]) /* ProcessGroupInformation */,
3730 sizeof(ULONG
) /* ProcessTokenVirtualizationEnabled */,
3731 sizeof(ULONG_PTR
) /* ProcessConsoleHostProcess */,
3732 sizeof(PROCESS_WINDOW_INFORMATION
) /* ProcessWindowInformation */,
3733 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION
) /* ProcessHandleInformation */,
3734 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION
) /* ProcessMitigationPolicy */,
3735 sizeof(ProcessDynamicFunctionTableInformation
) /* ProcessDynamicFunctionTableInformation */,
3736 sizeof(?) /* ProcessHandleCheckingMode */,
3737 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION
) /* ProcessKeepAliveCount */,
3738 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION
) /* ProcessRevokeFileHandles */,
3739 sizeof(PROCESS_WORKING_SET_CONTROL
) /* ProcessWorkingSetControl */,
3740 sizeof(?) /* ProcessHandleTable */,
3741 sizeof(?) /* ProcessCheckStackExtentsMode */,
3742 sizeof(buf
) /* ProcessCommandLineInformation */,
3743 sizeof(PS_PROTECTION
) /* ProcessProtectionInformation */,
3744 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO
) /* ProcessMemoryExhaustion */,
3745 sizeof(PROCESS_FAULT_INFORMATION
) /* ProcessFaultInformation */,
3746 sizeof(PROCESS_TELEMETRY_ID_INFORMATION
) /* ProcessTelemetryIdInformation */,
3747 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION
) /* ProcessCommitReleaseInformation */,
3748 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3749 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3750 0 /* ProcessReserved1Information */,
3751 0 /* ProcessReserved2Information */,
3752 sizeof(?) /* ProcessSubsystemProcess */,
3753 sizeof(PROCESS_JOB_MEMORY_INFO
) /* ProcessJobMemoryInformation */,
3756 ULONG i
, status
, ret_len
;
3757 BOOL is_current
= hproc
== GetCurrentProcess();
3759 if (!pNtQueryInformationProcess
)
3761 win_skip("NtQueryInformationProcess is not available on this platform\n");
3765 for (i
= 0; i
< ARRAY_SIZE(info_size
); i
++)
3768 status
= pNtQueryInformationProcess(hproc
, i
, buf
, info_size
[i
], &ret_len
);
3769 if (status
== STATUS_NOT_IMPLEMENTED
) continue;
3770 if (status
== STATUS_INVALID_INFO_CLASS
) continue;
3771 if (status
== STATUS_INFO_LENGTH_MISMATCH
) continue;
3775 case ProcessBasicInformation
:
3776 case ProcessQuotaLimits
:
3778 case ProcessPriorityClass
:
3779 case ProcessPriorityBoost
:
3780 case ProcessLUIDDeviceMapsEnabled
:
3781 case ProcessIoPriority
:
3782 case ProcessIoCounters
:
3783 case ProcessVmCounters
:
3784 case ProcessWow64Information
:
3785 case ProcessDefaultHardErrorMode
:
3786 case ProcessHandleCount
:
3787 case ProcessImageFileName
:
3788 case ProcessImageInformation
:
3789 case ProcessCycleTime
:
3790 case ProcessPagePriority
:
3791 case ProcessImageFileNameWin32
:
3792 ok(status
== STATUS_SUCCESS
, "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i
, status
, ret_len
);
3795 case ProcessAffinityMask
:
3796 case ProcessBreakOnTermination
:
3797 ok(status
== STATUS_ACCESS_DENIED
/* before win8 */ || status
== STATUS_SUCCESS
/* win8 is less strict */,
3798 "for info %lu expected STATUS_SUCCESS, got %08lx (ret_len %lu)\n", i
, status
, ret_len
);
3801 case ProcessDebugObjectHandle
:
3802 ok(status
== STATUS_ACCESS_DENIED
|| status
== STATUS_PORT_NOT_SET
,
3803 "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i
, status
, ret_len
);
3807 ok(status
== STATUS_SUCCESS
|| status
== STATUS_INVALID_PARAMETER
/* before win8 */,
3808 "for info %lu got %08lx (ret_len %lu)\n", i
, status
, ret_len
);
3810 ok(status
== STATUS_INVALID_PARAMETER
/* before win8 */ || status
== STATUS_ACCESS_DENIED
,
3811 "for info %lu got %08lx (ret_len %lu)\n", i
, status
, ret_len
);
3813 case ProcessExecuteFlags
:
3814 case ProcessDebugPort
:
3815 case ProcessDebugFlags
:
3817 ok(status
== STATUS_SUCCESS
|| status
== STATUS_INVALID_PARAMETER
,
3818 "for info %lu, got %08lx (ret_len %lu)\n", i
, status
, ret_len
);
3821 ok(status
== STATUS_ACCESS_DENIED
,
3822 "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i
, status
, ret_len
);
3827 ok(status
== STATUS_SUCCESS
|| status
== STATUS_UNSUCCESSFUL
|| status
== STATUS_INVALID_PARAMETER
,
3828 "for info %lu, got %08lx (ret_len %lu)\n", i
, status
, ret_len
);
3830 ok(status
== STATUS_ACCESS_DENIED
,
3831 "for info %lu expected STATUS_ACCESS_DENIED, got %08lx (ret_len %lu)\n", i
, status
, ret_len
);
3837 static void test_GetLogicalProcessorInformationEx(void)
3839 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*info
;
3843 if (!pGetLogicalProcessorInformationEx
)
3845 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3849 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, NULL
);
3850 ok(!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "got %d, error %ld\n", ret
, GetLastError());
3853 ret
= pGetLogicalProcessorInformationEx(RelationProcessorCore
, NULL
, &len
);
3854 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %ld\n", ret
, GetLastError());
3855 ok(len
> 0, "got %lu\n", len
);
3858 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, &len
);
3859 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %ld\n", ret
, GetLastError());
3860 ok(len
> 0, "got %lu\n", len
);
3862 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
3863 ret
= pGetLogicalProcessorInformationEx(RelationAll
, info
, &len
);
3864 ok(ret
, "got %d, error %ld\n", ret
, GetLastError());
3865 ok(info
->Size
> 0, "got %lu\n", info
->Size
);
3866 HeapFree(GetProcessHeap(), 0, info
);
3869 static void test_GetSystemCpuSetInformation(void)
3871 SYSTEM_CPU_SET_INFORMATION
*info
, *info_nt
;
3872 HANDLE process
= GetCurrentProcess();
3873 ULONG size
, expected_size
;
3878 if (!pGetSystemCpuSetInformation
)
3880 win_skip("GetSystemCpuSetInformation() is not supported.\n");
3886 expected_size
= sizeof(*info
) * si
.dwNumberOfProcessors
;
3890 /* Crashes on Windows with NULL return length. */
3891 pGetSystemCpuSetInformation(NULL
, 0, NULL
, process
, 0);
3895 SetLastError(0xdeadbeef);
3896 ret
= pGetSystemCpuSetInformation(NULL
, size
, &size
, process
, 0);
3897 ok(!ret
&& GetLastError() == ERROR_NOACCESS
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
3898 ok(!size
, "Got unexpected size %lu.\n", size
);
3901 SetLastError(0xdeadbeef);
3902 ret
= pGetSystemCpuSetInformation(NULL
, 0, &size
, (HANDLE
)0xdeadbeef, 0);
3903 ok(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
3904 ok(!size
, "Got unexpected size %lu.\n", size
);
3907 SetLastError(0xdeadbeef);
3908 ret
= pGetSystemCpuSetInformation(NULL
, 0, &size
, process
, 0);
3909 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
3910 ok(size
== expected_size
, "Got unexpected size %lu.\n", size
);
3912 info
= heap_alloc(size
);
3913 info_nt
= heap_alloc(size
);
3915 status
= pNtQuerySystemInformationEx(SystemCpuSetInformation
, &process
, sizeof(process
), info_nt
, expected_size
, NULL
);
3916 ok(!status
, "Got unexpected status %#lx.\n", status
);
3919 SetLastError(0xdeadbeef);
3920 ret
= pGetSystemCpuSetInformation(info
, expected_size
, &size
, process
, 0);
3921 ok(ret
&& GetLastError() == 0xdeadbeef, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
3922 ok(size
== expected_size
, "Got unexpected size %lu.\n", size
);
3924 ok(!memcmp(info
, info_nt
, expected_size
), "Info does not match NtQuerySystemInformationEx().\n");
3930 static void test_largepages(void)
3934 if (!pGetLargePageMinimum
) {
3935 win_skip("No GetLargePageMinimum support.\n");
3938 size
= pGetLargePageMinimum();
3940 ok((size
== 0) || (size
== 2*1024*1024) || (size
== 4*1024*1024), "GetLargePageMinimum reports %Id size\n", size
);
3943 struct proc_thread_attr
3950 struct _PROC_THREAD_ATTRIBUTE_LIST
3952 DWORD mask
; /* bitmask of items in list */
3953 DWORD size
; /* max number of items in list */
3954 DWORD count
; /* number of items in list */
3957 struct proc_thread_attr attrs
[10];
3960 static void test_ProcThreadAttributeList(void)
3963 SIZE_T size
, needed
;
3965 struct _PROC_THREAD_ATTRIBUTE_LIST list
, expect_list
;
3968 if (!pInitializeProcThreadAttributeList
)
3970 win_skip("No support for ProcThreadAttributeList\n");
3974 for (i
= 0; i
<= 10; i
++)
3976 needed
= FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST
, attrs
[i
]);
3977 ret
= pInitializeProcThreadAttributeList(NULL
, i
, 0, &size
);
3978 ok(!ret
, "got %d\n", ret
);
3979 if(i
>= 4 && GetLastError() == ERROR_INVALID_PARAMETER
) /* Vista only allows a maximium of 3 slots */
3981 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %ld\n", GetLastError());
3982 ok(size
== needed
, "%d: got %Id expect %Id\n", i
, size
, needed
);
3984 memset(&list
, 0xcc, sizeof(list
));
3985 ret
= pInitializeProcThreadAttributeList(&list
, i
, 0, &size
);
3986 ok(ret
, "got %d\n", ret
);
3987 ok(list
.mask
== 0, "%d: got %08lx\n", i
, list
.mask
);
3988 ok(list
.size
== i
, "%d: got %08lx\n", i
, list
.size
);
3989 ok(list
.count
== 0, "%d: got %08lx\n", i
, list
.count
);
3990 ok(list
.unk
== 0, "%d: got %08Ix\n", i
, list
.unk
);
3993 memset(handles
, 0, sizeof(handles
));
3994 memset(&expect_list
, 0xcc, sizeof(expect_list
));
3995 expect_list
.mask
= 0;
3996 expect_list
.size
= i
- 1;
3997 expect_list
.count
= 0;
3998 expect_list
.unk
= 0;
4000 ret
= pUpdateProcThreadAttribute(&list
, 0, 0xcafe, handles
, sizeof(PROCESSOR_NUMBER
), NULL
, NULL
);
4001 ok(!ret
, "got %d\n", ret
);
4002 ok(GetLastError() == ERROR_NOT_SUPPORTED
, "got %ld\n", GetLastError());
4004 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]) / 2, NULL
, NULL
);
4005 ok(!ret
, "got %d\n", ret
);
4006 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %ld\n", GetLastError());
4008 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]) * 2, NULL
, NULL
);
4009 ok(!ret
, "got %d\n", ret
);
4010 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %ld\n", GetLastError());
4012 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]), NULL
, NULL
);
4013 ok(ret
, "got %d\n", ret
);
4015 expect_list
.mask
|= 1 << ProcThreadAttributeParentProcess
;
4016 expect_list
.attrs
[0].attr
= PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
;
4017 expect_list
.attrs
[0].size
= sizeof(handles
[0]);
4018 expect_list
.attrs
[0].value
= handles
;
4019 expect_list
.count
++;
4021 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]), NULL
, NULL
);
4022 ok(!ret
, "got %d\n", ret
);
4023 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS
, "got %ld\n", GetLastError());
4025 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
) - 1, NULL
, NULL
);
4026 ok(!ret
, "got %d\n", ret
);
4027 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %ld\n", GetLastError());
4029 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
), NULL
, NULL
);
4030 ok(ret
, "got %d\n", ret
);
4032 expect_list
.mask
|= 1 << ProcThreadAttributeHandleList
;
4033 expect_list
.attrs
[1].attr
= PROC_THREAD_ATTRIBUTE_HANDLE_LIST
;
4034 expect_list
.attrs
[1].size
= sizeof(handles
);
4035 expect_list
.attrs
[1].value
= handles
;
4036 expect_list
.count
++;
4038 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
), NULL
, NULL
);
4039 ok(!ret
, "got %d\n", ret
);
4040 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS
, "got %ld\n", GetLastError());
4042 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR
, handles
, sizeof(PROCESSOR_NUMBER
), NULL
, NULL
);
4043 ok(ret
|| GetLastError() == ERROR_NOT_SUPPORTED
, "got %d gle %ld\n", ret
, GetLastError());
4047 expect_list
.mask
|= 1 << ProcThreadAttributeIdealProcessor
;
4048 expect_list
.attrs
[2].attr
= PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR
;
4049 expect_list
.attrs
[2].size
= sizeof(PROCESSOR_NUMBER
);
4050 expect_list
.attrs
[2].value
= handles
;
4051 expect_list
.count
++;
4054 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
, handles
, sizeof(handles
[0]), NULL
, NULL
);
4055 ok(ret
|| broken(GetLastError() == ERROR_NOT_SUPPORTED
), "got %d gle %ld\n", ret
, GetLastError());
4059 unsigned int i
= expect_list
.count
++;
4060 expect_list
.mask
|= 1 << ProcThreadAttributePseudoConsole
;
4061 expect_list
.attrs
[i
].attr
= PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
;
4062 expect_list
.attrs
[i
].size
= sizeof(HPCON
);
4063 expect_list
.attrs
[i
].value
= handles
;
4066 ok(!memcmp(&list
, &expect_list
, size
), "mismatch\n");
4068 pDeleteProcThreadAttributeList(&list
);
4071 /* level 0: Main test process
4072 * level 1: Process created by level 0 process without handle inheritance
4073 * level 2: Process created by level 1 process with handle inheritance and level 0
4074 * process parent substitute.
4075 * level 255: Process created by level 1 process during invalid parent handles testing. */
4076 static void test_parent_process_attribute(unsigned int level
, HANDLE read_pipe
)
4078 PROCESS_BASIC_INFORMATION pbi
;
4079 char buffer
[MAX_PATH
+ 64];
4080 HANDLE write_pipe
= NULL
;
4081 PROCESS_INFORMATION info
;
4082 SECURITY_ATTRIBUTES sa
;
4101 if (!pInitializeProcThreadAttributeList
)
4103 win_skip("No support for ProcThreadAttributeList.\n");
4107 memset(&sa
, 0, sizeof(sa
));
4108 sa
.nLength
= sizeof(sa
);
4109 sa
.bInheritHandle
= TRUE
;
4113 ret
= CreatePipe(&read_pipe
, &write_pipe
, &sa
, 0);
4114 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4116 parent_data
.parent
= OpenProcess(PROCESS_CREATE_PROCESS
| PROCESS_QUERY_INFORMATION
, TRUE
, GetCurrentProcessId());
4117 parent_data
.parent_id
= GetCurrentProcessId();
4121 status
= pNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation
, &pbi
, sizeof(pbi
), &pbi_size
);
4122 ok(status
== STATUS_SUCCESS
, "Got unexpected status %#lx.\n", status
);
4123 parent_id
= pbi
.InheritedFromUniqueProcessId
;
4125 memset(&parent_data
, 0, sizeof(parent_data
));
4126 ret
= ReadFile(read_pipe
, &parent_data
, sizeof(parent_data
), &size
, NULL
);
4127 ok((level
== 2 && ret
) || (level
== 1 && !ret
&& GetLastError() == ERROR_INVALID_HANDLE
),
4128 "Got unexpected ret %#x, level %u, GetLastError() %lu.\n",
4129 ret
, level
, GetLastError());
4134 ok(parent_id
== parent_data
.parent_id
, "Got parent id %lu, parent_data.parent_id %lu.\n",
4135 parent_id
, parent_data
.parent_id
);
4139 memset(&si
, 0, sizeof(si
));
4140 si
.StartupInfo
.cb
= sizeof(si
);
4147 ret
= pInitializeProcThreadAttributeList(NULL
, 1, 0, &size
);
4148 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
4149 "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4151 sprintf(buffer
, "\"%s\" process parent %u %p", selfname
, 255, read_pipe
);
4154 /* Crashes on some Windows installations, otherwise successfully creates process. */
4155 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
,
4156 NULL
, NULL
, (STARTUPINFOA
*)&si
, &info
);
4157 ok(ret
, "Got unexpected ret %#x, GetLastError() %u.\n", ret
, GetLastError());
4158 wait_and_close_child_process(&info
);
4160 si
.lpAttributeList
= heap_alloc(size
);
4161 ret
= pInitializeProcThreadAttributeList(si
.lpAttributeList
, 1, 0, &size
);
4162 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4163 handle
= OpenProcess(PROCESS_CREATE_PROCESS
, TRUE
, GetCurrentProcessId());
4164 ret
= pUpdateProcThreadAttribute(si
.lpAttributeList
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
,
4165 &handle
, sizeof(handle
), NULL
, NULL
);
4166 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4167 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, EXTENDED_STARTUPINFO_PRESENT
,
4168 NULL
, NULL
, (STARTUPINFOA
*)&si
, &info
);
4169 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4170 wait_and_close_child_process(&info
);
4171 CloseHandle(handle
);
4172 pDeleteProcThreadAttributeList(si
.lpAttributeList
);
4173 heap_free(si
.lpAttributeList
);
4175 si
.lpAttributeList
= heap_alloc(size
);
4176 ret
= pInitializeProcThreadAttributeList(si
.lpAttributeList
, 1, 0, &size
);
4177 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4178 handle
= (HANDLE
)0xdeadbeef;
4179 ret
= pUpdateProcThreadAttribute(si
.lpAttributeList
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
,
4180 &handle
, sizeof(handle
), NULL
, NULL
);
4181 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4182 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, EXTENDED_STARTUPINFO_PRESENT
,
4183 NULL
, NULL
, (STARTUPINFOA
*)&si
, &info
);
4184 ok(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
, "Got unexpected ret %#x, GetLastError() %lu.\n",
4185 ret
, GetLastError());
4186 pDeleteProcThreadAttributeList(si
.lpAttributeList
);
4187 heap_free(si
.lpAttributeList
);
4189 si
.lpAttributeList
= heap_alloc(size
);
4190 ret
= pInitializeProcThreadAttributeList(si
.lpAttributeList
, 1, 0, &size
);
4191 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4193 ret
= pUpdateProcThreadAttribute(si
.lpAttributeList
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
,
4194 &handle
, sizeof(handle
), NULL
, NULL
);
4195 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4196 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, EXTENDED_STARTUPINFO_PRESENT
,
4197 NULL
, NULL
, (STARTUPINFOA
*)&si
, &info
);
4198 ok(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
, "Got unexpected ret %#x, GetLastError() %lu.\n",
4199 ret
, GetLastError());
4200 pDeleteProcThreadAttributeList(si
.lpAttributeList
);
4201 heap_free(si
.lpAttributeList
);
4203 si
.lpAttributeList
= heap_alloc(size
);
4204 ret
= pInitializeProcThreadAttributeList(si
.lpAttributeList
, 1, 0, &size
);
4205 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4206 handle
= GetCurrentProcess();
4207 ret
= pUpdateProcThreadAttribute(si
.lpAttributeList
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
,
4208 &handle
, sizeof(handle
), NULL
, NULL
);
4209 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4210 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, EXTENDED_STARTUPINFO_PRESENT
,
4211 NULL
, NULL
, (STARTUPINFOA
*)&si
, &info
);
4212 /* Broken on Vista / w7 / w10. */
4213 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
),
4214 "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4216 wait_and_close_child_process(&info
);
4217 pDeleteProcThreadAttributeList(si
.lpAttributeList
);
4218 heap_free(si
.lpAttributeList
);
4220 si
.lpAttributeList
= heap_alloc(size
);
4221 ret
= pInitializeProcThreadAttributeList(si
.lpAttributeList
, 1, 0, &size
);
4222 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4224 parent
= OpenProcess(PROCESS_CREATE_PROCESS
, FALSE
, parent_id
);
4226 ret
= pUpdateProcThreadAttribute(si
.lpAttributeList
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
,
4227 &parent
, sizeof(parent
), NULL
, NULL
);
4228 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4231 sprintf(buffer
, "\"%s\" process parent %u %p", selfname
, level
+ 1, read_pipe
);
4232 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, level
== 1, level
== 1 ? EXTENDED_STARTUPINFO_PRESENT
: 0,
4233 NULL
, NULL
, (STARTUPINFOA
*)&si
, &info
);
4234 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4238 pDeleteProcThreadAttributeList(si
.lpAttributeList
);
4239 heap_free(si
.lpAttributeList
);
4240 CloseHandle(parent
);
4244 ret
= WriteFile(write_pipe
, &parent_data
, sizeof(parent_data
), &size
, NULL
);
4247 wait_and_close_child_process(&info
);
4251 CloseHandle(read_pipe
);
4252 CloseHandle(write_pipe
);
4253 CloseHandle(parent_data
.parent
);
4257 static void test_handle_list_attribute(BOOL child
, HANDLE handle1
, HANDLE handle2
)
4259 char buffer
[MAX_PATH
+ 64];
4261 PROCESS_INFORMATION info
;
4265 SECURITY_ATTRIBUTES sa
;
4269 char name1
[256], name2
[256];
4273 ret
= GetHandleInformation(handle1
, &flags
);
4274 ok(ret
, "Failed to get handle info, error %ld.\n", GetLastError());
4275 ok(flags
== HANDLE_FLAG_INHERIT
, "Unexpected flags %#lx.\n", flags
);
4276 ret
= GetFileInformationByHandleEx(handle1
, FileNameInfo
, name1
, sizeof(name1
));
4277 ok(ret
, "Failed to get pipe name, error %ld\n", GetLastError());
4278 CloseHandle(handle1
);
4280 ret
= GetHandleInformation(handle2
, &flags
);
4283 ok(!(flags
& HANDLE_FLAG_INHERIT
), "Parent's handle shouldn't have been inherited\n");
4284 ret
= GetFileInformationByHandleEx(handle2
, FileNameInfo
, name2
, sizeof(name2
));
4285 ok(!ret
|| strcmp(name1
, name2
), "Parent's handle shouldn't have been inherited\n");
4288 ok(GetLastError() == ERROR_INVALID_HANDLE
, "Unexpected return value, error %ld.\n", GetLastError());
4293 ret
= pInitializeProcThreadAttributeList(NULL
, 1, 0, &size
);
4294 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
4295 "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4297 memset(&si
, 0, sizeof(si
));
4298 si
.StartupInfo
.cb
= sizeof(si
);
4299 si
.lpAttributeList
= heap_alloc(size
);
4300 ret
= pInitializeProcThreadAttributeList(si
.lpAttributeList
, 1, 0, &size
);
4301 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4303 memset(&sa
, 0, sizeof(sa
));
4304 sa
.nLength
= sizeof(sa
);
4305 sa
.bInheritHandle
= TRUE
;
4307 ret
= CreatePipe(&pipe
[0], &pipe
[1], &sa
, 1024);
4308 ok(ret
, "Failed to create a pipe.\n");
4310 ret
= pUpdateProcThreadAttribute(si
.lpAttributeList
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, &pipe
[0],
4311 sizeof(pipe
[0]), NULL
, NULL
);
4312 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4314 sprintf(buffer
, "\"%s\" process handlelist %p %p", selfname
, pipe
[0], pipe
[1]);
4315 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, EXTENDED_STARTUPINFO_PRESENT
, NULL
, NULL
,
4316 (STARTUPINFOA
*)&si
, &info
);
4317 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4319 wait_and_close_child_process(&info
);
4321 CloseHandle(pipe
[0]);
4322 CloseHandle(pipe
[1]);
4325 static void test_dead_process(void)
4327 DWORD_PTR data
[256];
4328 PROCESS_BASIC_INFORMATION basic
;
4329 SYSTEM_PROCESS_INFORMATION
*spi
;
4330 SECTION_IMAGE_INFORMATION image
;
4331 PROCESS_INFORMATION pi
;
4332 PROCESS_PRIORITY_CLASS
*prio
= (PROCESS_PRIORITY_CLASS
*)data
;
4333 BYTE
*buffer
= NULL
;
4339 create_process("exit", &pi
);
4340 wait_child_process(pi
.hProcess
);
4343 memset( data
, 0, sizeof(data
) );
4344 status
= NtQueryInformationProcess( pi
.hProcess
, ProcessImageFileName
, data
, sizeof(data
), NULL
);
4345 ok( !status
, "ProcessImageFileName failed %lx\n", status
);
4346 ok( ((UNICODE_STRING
*)data
)->Length
, "ProcessImageFileName not set\n" );
4347 ok( ((UNICODE_STRING
*)data
)->Buffer
[0] == '\\', "ProcessImageFileName not set\n" );
4349 memset( prio
, 0xcc, sizeof(*prio
) );
4350 status
= NtQueryInformationProcess( pi
.hProcess
, ProcessPriorityClass
, prio
, sizeof(*prio
), NULL
);
4351 ok( !status
, "ProcessPriorityClass failed %lx\n", status
);
4352 ok( prio
->PriorityClass
!= 0xcc, "ProcessPriorityClass not set\n" );
4354 memset( &basic
, 0xcc, sizeof(basic
) );
4355 status
= NtQueryInformationProcess( pi
.hProcess
, ProcessBasicInformation
, &basic
, sizeof(basic
), NULL
);
4356 ok( !status
, "ProcessBasicInformation failed %lx\n", status
);
4357 ok( basic
.ExitStatus
== 0, "ProcessBasicInformation info modified\n" );
4359 memset( &image
, 0xcc, sizeof(image
) );
4360 status
= NtQueryInformationProcess( pi
.hProcess
, ProcessImageInformation
, &image
, sizeof(image
), NULL
);
4361 ok( status
== STATUS_PROCESS_IS_TERMINATING
, "ProcessImageInformation wrong error %lx\n", status
);
4362 ok( image
.Machine
== 0xcccc, "ProcessImageInformation info modified\n" );
4364 while ((status
= NtQuerySystemInformation(SystemProcessInformation
, buffer
, size
, &size
)) == STATUS_INFO_LENGTH_MISMATCH
)
4367 buffer
= malloc(size
);
4369 ok(status
== STATUS_SUCCESS
, "got %#lx\n", status
);
4373 spi
= (SYSTEM_PROCESS_INFORMATION
*)(buffer
+ offset
);
4374 if (spi
->UniqueProcessId
== ULongToHandle(pi
.dwProcessId
))
4379 offset
+= spi
->NextEntryOffset
;
4380 } while (spi
->NextEntryOffset
);
4381 ok( !found
, "process still enumerated\n" );
4382 CloseHandle(pi
.hProcess
);
4383 CloseHandle(pi
.hThread
);
4386 static void test_nested_jobs_child(unsigned int index
)
4388 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
4389 HANDLE job
, job_parent
, job_other
, port
;
4390 PROCESS_INFORMATION pi
;
4391 OVERLAPPED
*overlapped
;
4398 sprintf(job_name
, "test_nested_jobs_%u", index
);
4399 job
= pOpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS
| JOB_OBJECT_SET_ATTRIBUTES
| JOB_OBJECT_QUERY
4400 | JOB_OBJECT_TERMINATE
, FALSE
, job_name
);
4401 ok(!!job
, "OpenJobObjectA error %lu\n", GetLastError());
4403 sprintf(job_name
, "test_nested_jobs_%u", !index
);
4404 job_other
= pOpenJobObjectA(JOB_OBJECT_ASSIGN_PROCESS
| JOB_OBJECT_SET_ATTRIBUTES
| JOB_OBJECT_QUERY
4405 | JOB_OBJECT_TERMINATE
, FALSE
, job_name
);
4406 ok(!!job_other
, "OpenJobObjectA error %lu\n", GetLastError());
4408 job_parent
= pCreateJobObjectW(NULL
, NULL
);
4409 ok(!!job_parent
, "CreateJobObjectA error %lu\n", GetLastError());
4411 ret
= pAssignProcessToJobObject(job_parent
, GetCurrentProcess());
4412 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
4414 create_process("wait", &pi
);
4416 ret
= pAssignProcessToJobObject(job_parent
, pi
.hProcess
);
4417 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
) /* Supported since Windows 8. */,
4418 "AssignProcessToJobObject error %lu\n", GetLastError());
4421 win_skip("Nested jobs are not supported.\n");
4424 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
4425 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
4428 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
4429 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4430 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4433 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
4434 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4435 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4438 ret
= pIsProcessInJob(GetCurrentProcess(), job
, &out
);
4439 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4440 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
4443 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
4444 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4445 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4447 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
4448 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
4450 TerminateProcess(pi
.hProcess
, 0);
4451 wait_child_process(pi
.hProcess
);
4452 CloseHandle(pi
.hProcess
);
4453 CloseHandle(pi
.hThread
);
4455 dead_pid
= pi
.dwProcessId
;
4457 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
4458 ok(!!port
, "CreateIoCompletionPort error %lu\n", GetLastError());
4460 port_info
.CompletionPort
= port
;
4461 port_info
.CompletionKey
= job
;
4462 ret
= pSetInformationJobObject(job
, JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
4463 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
4464 port_info
.CompletionKey
= job_parent
;
4465 ret
= pSetInformationJobObject(job_parent
, JobObjectAssociateCompletionPortInformation
,
4466 &port_info
, sizeof(port_info
));
4467 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
4469 create_process("wait", &pi
);
4471 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
4472 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4473 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4476 ret
= pIsProcessInJob(pi
.hProcess
, job_parent
, &out
);
4477 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4478 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4480 /* The first already dead child process still shows up randomly. */
4483 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, 0);
4484 } while (ret
&& (ULONG_PTR
)overlapped
== dead_pid
);
4486 ok(ret
, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4487 ok(key
== JOB_OBJECT_MSG_NEW_PROCESS
, "unexpected key %lx\n", key
);
4488 ok((HANDLE
)value
== job
, "unexpected value %p\n", (void *)value
);
4489 ok((ULONG_PTR
)overlapped
== GetCurrentProcessId(), "unexpected pid %#lx\n", (DWORD
)(DWORD_PTR
)overlapped
);
4493 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, 0);
4494 } while (ret
&& (ULONG_PTR
)overlapped
== dead_pid
);
4496 ok(ret
, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4497 ok(key
== JOB_OBJECT_MSG_NEW_PROCESS
, "unexpected key %lx\n", key
);
4498 ok((HANDLE
)value
== job_parent
, "unexpected value %p\n", (void *)value
);
4499 ok((ULONG_PTR
)overlapped
== GetCurrentProcessId(), "unexpected pid %#lx\n", (DWORD
)(DWORD_PTR
)overlapped
);
4501 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
4502 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job_parent
, pi
.dwProcessId
, 0);
4504 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, 0);
4505 ok(!ret
, "GetQueuedCompletionStatus succeeded.\n");
4509 ret
= pAssignProcessToJobObject(job_other
, GetCurrentProcess());
4510 ok(!ret
, "AssignProcessToJobObject succeeded\n");
4511 ok(GetLastError() == ERROR_ACCESS_DENIED
, "Got unexpected error %lu.\n", GetLastError());
4517 TerminateProcess(pi
.hProcess
, 0);
4518 wait_child_process(pi
.hProcess
);
4520 CloseHandle(pi
.hProcess
);
4521 CloseHandle(pi
.hThread
);
4522 CloseHandle(job_parent
);
4524 CloseHandle(job_other
);
4527 static void test_nested_jobs(void)
4529 BOOL ret
, already_in_job
= TRUE
, create_succeeded
= FALSE
;
4530 PROCESS_INFORMATION info
[2];
4531 char buffer
[MAX_PATH
+ 26];
4532 STARTUPINFOA si
= {0};
4536 if (!pIsProcessInJob
)
4538 win_skip("IsProcessInJob not available.\n");
4542 job1
= pCreateJobObjectW(NULL
, NULL
);
4543 ok(!!job1
, "CreateJobObjectW failed, error %lu.\n", GetLastError());
4544 job2
= pCreateJobObjectW(NULL
, NULL
);
4545 ok(!!job2
, "CreateJobObjectW failed, error %lu.\n", GetLastError());
4547 create_succeeded
= TRUE
;
4548 sprintf(buffer
, "\"%s\" process wait", selfname
);
4549 for (i
= 0; i
< 2; ++i
)
4551 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &info
[i
]);
4552 if (!ret
&& GetLastError() == ERROR_ACCESS_DENIED
)
4554 create_succeeded
= FALSE
;
4557 ok(ret
, "CreateProcessA error %lu\n", GetLastError());
4560 if (create_succeeded
)
4562 ret
= pIsProcessInJob(info
[0].hProcess
, NULL
, &already_in_job
);
4563 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4565 if (!already_in_job
)
4567 ret
= pAssignProcessToJobObject(job2
, info
[1].hProcess
);
4568 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
4570 ret
= pAssignProcessToJobObject(job1
, info
[0].hProcess
);
4571 ok(ret
, "AssignProcessToJobObject error %lu\n", GetLastError());
4573 ret
= pAssignProcessToJobObject(job2
, info
[0].hProcess
);
4574 ok(!ret
, "AssignProcessToJobObject succeeded\n");
4575 ok(GetLastError() == ERROR_ACCESS_DENIED
, "Got unexpected error %lu.\n", GetLastError());
4577 TerminateProcess(info
[1].hProcess
, 0);
4578 wait_child_process(info
[1].hProcess
);
4579 CloseHandle(info
[1].hProcess
);
4580 CloseHandle(info
[1].hThread
);
4582 ret
= pAssignProcessToJobObject(job2
, info
[0].hProcess
);
4583 ok(!ret
, "AssignProcessToJobObject succeeded\n");
4584 ok(GetLastError() == ERROR_ACCESS_DENIED
, "Got unexpected error %lu.\n", GetLastError());
4587 TerminateProcess(info
[0].hProcess
, 0);
4588 wait_child_process(info
[0].hProcess
);
4589 CloseHandle(info
[0].hProcess
);
4590 CloseHandle(info
[0].hThread
);
4595 win_skip("Test process is already in job, can't test parenting non-empty job.\n");
4601 job1
= pCreateJobObjectW(NULL
, L
"test_nested_jobs_0");
4602 ok(!!job1
, "CreateJobObjectW failed, error %lu.\n", GetLastError());
4603 job2
= pCreateJobObjectW(NULL
, L
"test_nested_jobs_1");
4604 ok(!!job2
, "CreateJobObjectW failed, error %lu.\n", GetLastError());
4606 sprintf(buffer
, "\"%s\" process nested_jobs 0", selfname
);
4607 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &info
[0]),
4608 "CreateProcess failed\n");
4609 wait_child_process(info
[0].hProcess
);
4610 sprintf(buffer
, "\"%s\" process nested_jobs 1", selfname
);
4611 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &info
[1]),
4612 "CreateProcess failed\n");
4613 wait_child_process(info
[1].hProcess
);
4614 for (i
= 0; i
< 2; ++i
)
4616 CloseHandle(info
[i
].hProcess
);
4617 CloseHandle(info
[i
].hThread
);
4624 static void test_job_list_attribute(HANDLE parent_job
)
4626 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION job_info
;
4627 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
4628 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
4629 PPROC_THREAD_ATTRIBUTE_LIST attrs
;
4630 char buffer
[MAX_PATH
+ 19];
4631 PROCESS_INFORMATION pi
;
4632 OVERLAPPED
*overlapped
;
4633 HANDLE jobs
[2], port
;
4641 if (!pInitializeProcThreadAttributeList
)
4643 win_skip("No support for ProcThreadAttributeList\n");
4647 ret
= pInitializeProcThreadAttributeList(NULL
, 1, 0, &size
);
4648 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
4649 "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4650 attrs
= heap_alloc(size
);
4653 jobs
[0] = (HANDLE
)0xdeadbeef;
4656 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4657 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4658 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
,
4659 sizeof(*jobs
), NULL
, NULL
);
4660 if (!ret
&& GetLastError() == ERROR_NOT_SUPPORTED
)
4662 /* Supported since Win10. */
4663 win_skip("PROC_THREAD_ATTRIBUTE_JOB_LIST is not supported.\n");
4664 pDeleteProcThreadAttributeList(attrs
);
4668 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4670 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4671 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4672 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
,
4674 ok(!ret
&& GetLastError() == ERROR_BAD_LENGTH
, "Got unexpected ret %#x, GetLastError() %lu.\n",
4675 ret
, GetLastError());
4677 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4678 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4679 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
,
4680 sizeof(*jobs
) * 2, NULL
, NULL
);
4681 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4683 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4684 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4685 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
,
4686 sizeof(*jobs
), NULL
, NULL
);
4688 memset(&si
, 0, sizeof(si
));
4689 si
.StartupInfo
.cb
= sizeof(si
);
4690 si
.lpAttributeList
= attrs
;
4691 sprintf(buffer
, "\"%s\" process wait", selfname
);
4693 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
, NULL
, NULL
,
4694 (STARTUPINFOA
*)&si
, &pi
);
4695 ok(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
, "Got unexpected ret %#x, GetLastError() %lu.\n",
4696 ret
, GetLastError());
4698 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4699 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4700 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
+ 1,
4701 sizeof(*jobs
), NULL
, NULL
);
4702 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
, NULL
, NULL
,
4703 (STARTUPINFOA
*)&si
, &pi
);
4704 ok(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
, "Got unexpected ret %#x, GetLastError() %lu.\n",
4705 ret
, GetLastError());
4707 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4708 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4709 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, &parent_job
,
4710 sizeof(parent_job
), NULL
, NULL
);
4711 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
, NULL
, NULL
,
4712 (STARTUPINFOA
*)&si
, &pi
);
4713 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4715 ret
= pIsProcessInJob(pi
.hProcess
, parent_job
, &out
);
4716 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4717 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4719 TerminateProcess(pi
.hProcess
, 0);
4720 wait_and_close_child_process(&pi
);
4722 jobs
[0] = pCreateJobObjectW(NULL
, NULL
);
4723 ok(!!jobs
[0], "CreateJobObjectA error %lu\n", GetLastError());
4724 jobs
[1] = pCreateJobObjectW(NULL
, NULL
);
4725 ok(!!jobs
[1], "CreateJobObjectA error %lu\n", GetLastError());
4727 /* Breakaway works for the inherited job only. */
4728 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
4729 ret
= pSetInformationJobObject(parent_job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
4730 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
4731 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
4732 | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
4733 ret
= pSetInformationJobObject(jobs
[1], JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
4734 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
4736 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4737 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4738 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
+ 1,
4739 sizeof(*jobs
), NULL
, NULL
);
4740 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
4741 | CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, (STARTUPINFOA
*)&si
, &pi
);
4742 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4744 ret
= pIsProcessInJob(pi
.hProcess
, parent_job
, &out
);
4745 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4746 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
4748 ret
= pIsProcessInJob(pi
.hProcess
, jobs
[1], &out
);
4749 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4750 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4752 ret
= pIsProcessInJob(pi
.hProcess
, jobs
[0], &out
);
4753 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4754 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
4756 TerminateProcess(pi
.hProcess
, 0);
4757 wait_and_close_child_process(&pi
);
4759 CloseHandle(jobs
[1]);
4760 jobs
[1] = pCreateJobObjectW(NULL
, NULL
);
4761 ok(!!jobs
[1], "CreateJobObjectA error %lu\n", GetLastError());
4763 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4764 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4765 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
+ 1,
4766 sizeof(*jobs
), NULL
, NULL
);
4767 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
,
4768 NULL
, NULL
, (STARTUPINFOA
*)&si
, &pi
);
4769 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4771 ret
= pIsProcessInJob(pi
.hProcess
, parent_job
, &out
);
4772 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4773 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4775 ret
= pIsProcessInJob(pi
.hProcess
, jobs
[1], &out
);
4776 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4777 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4779 ret
= pIsProcessInJob(pi
.hProcess
, jobs
[0], &out
);
4780 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4781 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
4783 TerminateProcess(pi
.hProcess
, 0);
4784 wait_and_close_child_process(&pi
);
4786 ret
= pQueryInformationJobObject(jobs
[0], JobObjectBasicAccountingInformation
, &job_info
,
4787 sizeof(job_info
), NULL
);
4788 ok(ret
, "QueryInformationJobObject error %lu\n", GetLastError());
4789 ok(!job_info
.TotalProcesses
, "Got unexpected TotalProcesses %lu.\n", job_info
.TotalProcesses
);
4790 ok(!job_info
.ActiveProcesses
, "Got unexpected ActiveProcesses %lu.\n", job_info
.ActiveProcesses
);
4792 ret
= pQueryInformationJobObject(jobs
[1], JobObjectBasicAccountingInformation
, &job_info
,
4793 sizeof(job_info
), NULL
);
4794 ok(ret
, "QueryInformationJobObject error %lu\n", GetLastError());
4795 ok(job_info
.TotalProcesses
== 1, "Got unexpected TotalProcesses %lu.\n", job_info
.TotalProcesses
);
4796 ok(!job_info
.ActiveProcesses
|| job_info
.ActiveProcesses
== 1, "Got unexpected ActiveProcesses %lu.\n",
4797 job_info
.ActiveProcesses
);
4799 /* Fails due to the second job already has the parent other than the first job in the list. */
4800 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4801 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4802 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
,
4803 2 * sizeof(*jobs
), NULL
, NULL
);
4805 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
4806 ok(!!port
, "CreateIoCompletionPort error %lu\n", GetLastError());
4808 port_info
.CompletionPort
= port
;
4809 port_info
.CompletionKey
= jobs
[0];
4810 ret
= pSetInformationJobObject(jobs
[0], JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
4811 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
4813 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, 0);
4814 ok(!ret
, "GetQueuedCompletionStatus succeeded.\n");
4816 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
, NULL
, NULL
,
4817 (STARTUPINFOA
*)&si
, &pi
);
4818 ok(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
, "Got unexpected ret %#x, GetLastError() %lu.\n",
4819 ret
, GetLastError());
4821 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, 100);
4822 ok(ret
, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4823 ok(key
== JOB_OBJECT_MSG_NEW_PROCESS
, "unexpected key %lx\n", key
);
4824 ok((HANDLE
)value
== jobs
[0], "unexpected value %p\n", (void *)value
);
4825 ok(!!overlapped
, "Got zero pid.\n");
4827 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, 100);
4828 ok(ret
, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4829 ok(key
== JOB_OBJECT_MSG_EXIT_PROCESS
, "unexpected key %lx\n", key
);
4830 ok((HANDLE
)value
== jobs
[0], "unexpected value %p\n", (void *)value
);
4831 ok(!!overlapped
, "Got zero pid.\n");
4833 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, 100);
4834 ok(ret
, "GetQueuedCompletionStatus: %lx\n", GetLastError());
4835 ok(key
== JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
, "unexpected key %lx\n", key
);
4836 ok((HANDLE
)value
== jobs
[0], "unexpected value %p\n", (void *)value
);
4837 ok(!overlapped
, "Got unexpected overlapped %p.\n", overlapped
);
4839 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, 0);
4840 ok(!ret
, "GetQueuedCompletionStatus succeeded.\n");
4844 /* The first job got updated even though the process creation failed. */
4845 ret
= pQueryInformationJobObject(jobs
[0], JobObjectBasicAccountingInformation
, &job_info
,
4846 sizeof(job_info
), NULL
);
4847 ok(ret
, "QueryInformationJobObject error %lu\n", GetLastError());
4848 ok(job_info
.TotalProcesses
== 1, "Got unexpected TotalProcesses %lu.\n", job_info
.TotalProcesses
);
4849 ok(!job_info
.ActiveProcesses
, "Got unexpected ActiveProcesses %lu.\n", job_info
.ActiveProcesses
);
4851 ret
= pQueryInformationJobObject(jobs
[1], JobObjectBasicAccountingInformation
, &job_info
,
4852 sizeof(job_info
), NULL
);
4853 ok(ret
, "QueryInformationJobObject error %lu\n", GetLastError());
4854 ok(job_info
.TotalProcesses
== 1, "Got unexpected TotalProcesses %lu.\n", job_info
.TotalProcesses
);
4855 ok(!job_info
.ActiveProcesses
, "Got unexpected ActiveProcesses %lu.\n", job_info
.ActiveProcesses
);
4857 /* Check that the first job actually got the job_parent as parent. */
4858 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4859 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4860 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
,
4861 sizeof(*jobs
), NULL
, NULL
);
4862 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
4863 | CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, (STARTUPINFOA
*)&si
, &pi
);
4864 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4866 ret
= pIsProcessInJob(pi
.hProcess
, parent_job
, &out
);
4867 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4868 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4870 ret
= pIsProcessInJob(pi
.hProcess
, jobs
[0], &out
);
4871 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4872 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4874 TerminateProcess(pi
.hProcess
, 0);
4875 wait_and_close_child_process(&pi
);
4881 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4882 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4883 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
,
4884 2 * sizeof(*jobs
), NULL
, NULL
);
4885 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
, NULL
, NULL
,
4886 (STARTUPINFOA
*)&si
, &pi
);
4887 ok(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
, "Got unexpected ret %#x, GetLastError() %lu.\n",
4888 ret
, GetLastError());
4890 CloseHandle(jobs
[0]);
4891 CloseHandle(jobs
[1]);
4893 jobs
[0] = pCreateJobObjectW(NULL
, NULL
);
4894 ok(!!jobs
[0], "CreateJobObjectA error %lu\n", GetLastError());
4895 jobs
[1] = pCreateJobObjectW(NULL
, NULL
);
4896 ok(!!jobs
[1], "CreateJobObjectA error %lu\n", GetLastError());
4898 /* Create the job chain successfully and check the job chain. */
4899 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4900 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4901 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
,
4902 2 * sizeof(*jobs
), NULL
, NULL
);
4903 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
,
4904 NULL
, NULL
, (STARTUPINFOA
*)&si
, &pi
);
4905 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4907 ret
= pIsProcessInJob(pi
.hProcess
, parent_job
, &out
);
4908 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4909 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4911 ret
= pIsProcessInJob(pi
.hProcess
, jobs
[0], &out
);
4912 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4913 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4915 ret
= pIsProcessInJob(pi
.hProcess
, jobs
[1], &out
);
4916 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4917 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4919 TerminateProcess(pi
.hProcess
, 0);
4920 wait_and_close_child_process(&pi
);
4922 ret
= pInitializeProcThreadAttributeList(attrs
, 1, 0, &size
);
4923 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4924 ret
= pUpdateProcThreadAttribute(attrs
, 0, PROC_THREAD_ATTRIBUTE_JOB_LIST
, jobs
+ 1,
4925 sizeof(*jobs
), NULL
, NULL
);
4926 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, EXTENDED_STARTUPINFO_PRESENT
4927 | CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, (STARTUPINFOA
*)&si
, &pi
);
4928 ok(ret
, "Got unexpected ret %#x, GetLastError() %lu.\n", ret
, GetLastError());
4930 ret
= pIsProcessInJob(pi
.hProcess
, parent_job
, &out
);
4931 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4932 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4934 ret
= pIsProcessInJob(pi
.hProcess
, jobs
[0], &out
);
4935 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4936 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4938 ret
= pIsProcessInJob(pi
.hProcess
, jobs
[1], &out
);
4939 ok(ret
, "IsProcessInJob error %lu\n", GetLastError());
4940 ok(out
, "IsProcessInJob returned out=%u\n", out
);
4942 TerminateProcess(pi
.hProcess
, 0);
4943 wait_and_close_child_process(&pi
);
4945 CloseHandle(jobs
[0]);
4946 CloseHandle(jobs
[1]);
4948 pDeleteProcThreadAttributeList(attrs
);
4951 limit_info
.BasicLimitInformation
.LimitFlags
= 0;
4952 ret
= pSetInformationJobObject(parent_job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
4953 ok(ret
, "SetInformationJobObject error %lu\n", GetLastError());
4956 static void test_services_exe(void)
4959 ULONG size
, offset
, try;
4961 SYSTEM_PROCESS_INFORMATION
*spi
;
4962 ULONG services_pid
= 0, services_session_id
= ~0;
4964 /* Check that passing a zero size returns a size suitable for the next call,
4965 * taking into account that in rare cases processes may start between the
4966 * two NtQuerySystemInformation() calls. So this may require a few tries.
4968 for (try = 0; try < 3; try++)
4970 status
= NtQuerySystemInformation(SystemProcessInformation
, NULL
, 0, &size
);
4971 ok(status
== STATUS_INFO_LENGTH_MISMATCH
, "got %#lx\n", status
);
4974 status
= NtQuerySystemInformation(SystemProcessInformation
, buf
, size
, &size
);
4975 if (status
!= STATUS_INFO_LENGTH_MISMATCH
) break;
4978 ok(status
== STATUS_SUCCESS
, "got %#lx\n", status
);
4980 spi
= (SYSTEM_PROCESS_INFORMATION
*)buf
;
4985 spi
= (SYSTEM_PROCESS_INFORMATION
*)(buf
+ offset
);
4986 if (!wcsnicmp(spi
->ProcessName
.Buffer
, L
"services.exe", spi
->ProcessName
.Length
/sizeof(WCHAR
)))
4988 services_pid
= HandleToUlong(spi
->UniqueProcessId
);
4989 services_session_id
= spi
->SessionId
;
4991 offset
+= spi
->NextEntryOffset
;
4992 } while (spi
->NextEntryOffset
!= 0);
4994 ok(services_pid
!= 0, "services.exe not found\n");
4996 ok(services_session_id
== 0, "got services.exe SessionId %lu\n", services_session_id
);
5001 HANDLE job
, hproc
, h
, h2
;
5003 ok(b
, "Basic init of CreateProcess test\n");
5008 if (!strcmp(myARGV
[2], "dump") && myARGC
>= 4)
5010 doChild(myARGV
[3], (myARGC
>= 5) ? myARGV
[4] : NULL
);
5013 else if (!strcmp(myARGV
[2], "wait"))
5016 ok(0, "Child process not killed\n");
5019 else if (!strcmp(myARGV
[2], "sync") && myARGC
>= 4)
5021 HANDLE sem
= OpenSemaphoreA(SYNCHRONIZE
, FALSE
, myARGV
[3]);
5022 ok(sem
!= 0, "OpenSemaphoreA(%s) failed le=%lu\n", myARGV
[3], GetLastError());
5025 DWORD ret
= WaitForSingleObject(sem
, 30000);
5026 ok(ret
== WAIT_OBJECT_0
, "WaitForSingleObject(%s) returned %lu\n", myARGV
[3], ret
);
5031 else if (!strcmp(myARGV
[2], "exit"))
5035 else if (!strcmp(myARGV
[2], "nested") && myARGC
>= 4)
5037 char buffer
[MAX_PATH
+ 26];
5038 STARTUPINFOA startup
;
5039 PROCESS_INFORMATION info
;
5042 memset(&startup
, 0, sizeof(startup
));
5043 startup
.cb
= sizeof(startup
);
5044 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
5045 startup
.wShowWindow
= SW_SHOWNORMAL
;
5047 sprintf(buffer
, "\"%s\" process dump \"%s\"", selfname
, myARGV
[3]);
5048 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
5049 CloseHandle(info
.hProcess
);
5050 CloseHandle(info
.hThread
);
5052 /* The nested process is suspended so we can use the same resource
5053 * file and it's up to the parent to read it before resuming the
5056 hFile
= CreateFileA(myARGV
[3], GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
5057 childPrintf(hFile
, "[Nested]\nPid=%08lu\n", info
.dwProcessId
);
5061 else if (!strcmp(myARGV
[2], "parent") && myARGC
>= 5)
5063 sscanf(myARGV
[4], "%p", &h
);
5064 test_parent_process_attribute(atoi(myARGV
[3]), h
);
5067 else if (!strcmp(myARGV
[2], "handlelist") && myARGC
>= 5)
5069 sscanf(myARGV
[3], "%p", &h
);
5070 sscanf(myARGV
[4], "%p", &h2
);
5071 test_handle_list_attribute(TRUE
, h
, h2
);
5074 else if (!strcmp(myARGV
[2], "nested_jobs") && myARGC
>= 4)
5076 test_nested_jobs_child(atoi(myARGV
[3]));
5080 ok(0, "Unexpected command %s\n", myARGV
[2]);
5083 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
5086 test_process_info(hproc
);
5090 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
5091 test_process_info(GetCurrentProcess());
5092 test_TerminateProcess();
5099 test_DebuggingFlag();
5103 test_GetProcessVersion();
5104 test_GetProcessImageFileNameA();
5105 test_QueryFullProcessImageNameA();
5106 test_QueryFullProcessImageNameW();
5108 test_IsWow64Process();
5109 test_IsWow64Process2();
5111 test_ProcessorCount();
5112 test_RegistryQuota();
5113 test_DuplicateHandle();
5114 test_StartupNoConsole();
5115 test_DetachConsoleHandles();
5116 test_DetachStdHandles();
5117 test_GetNumaProcessorNode();
5118 test_session_info();
5119 test_GetLogicalProcessorInformationEx();
5120 test_GetSystemCpuSetInformation();
5122 test_ProcThreadAttributeList();
5123 test_SuspendProcessState();
5124 test_SuspendProcessNewThread();
5125 test_parent_process_attribute(0, NULL
);
5126 test_handle_list_attribute(FALSE
, NULL
, NULL
);
5127 test_dead_process();
5128 test_services_exe();
5130 /* things that can be tested:
5131 * lookup: check the way program to be executed is searched
5132 * handles: check the handle inheritance stuff (+sec options)
5133 * console: check if console creation parameters work
5136 if (!pCreateJobObjectW
)
5138 win_skip("No job object support\n");
5142 test_IsProcessInJob();
5143 test_TerminateJobObject();
5144 test_QueryInformationJobObject();
5145 test_CompletionPort();
5146 test_KillOnJobClose();
5147 test_WaitForJobObject();
5149 job
= test_AddSelfToJob();
5150 test_jobInheritance(job
);
5151 test_job_list_attribute(job
);
5152 test_BreakawayOk(job
);