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"
42 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
43 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
44 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
45 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
47 #define expect_eq_d(expected, actual) \
49 int value = (actual); \
50 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
53 #define expect_eq_s(expected, actual) \
55 LPCSTR value = (actual); \
56 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
59 #define expect_eq_ws_i(expected, actual) \
61 LPCWSTR value = (actual); \
62 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
63 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
66 static HINSTANCE hkernel32
, hntdll
;
67 static void (WINAPI
*pGetNativeSystemInfo
)(LPSYSTEM_INFO
);
68 static BOOL (WINAPI
*pGetSystemRegistryQuota
)(PDWORD
, PDWORD
);
69 static BOOL (WINAPI
*pIsWow64Process
)(HANDLE
,PBOOL
);
70 static LPVOID (WINAPI
*pVirtualAllocEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
, DWORD
);
71 static BOOL (WINAPI
*pVirtualFreeEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
);
72 static BOOL (WINAPI
*pQueryFullProcessImageNameA
)(HANDLE hProcess
, DWORD dwFlags
, LPSTR lpExeName
, PDWORD lpdwSize
);
73 static BOOL (WINAPI
*pQueryFullProcessImageNameW
)(HANDLE hProcess
, DWORD dwFlags
, LPWSTR lpExeName
, PDWORD lpdwSize
);
74 static DWORD (WINAPI
*pK32GetProcessImageFileNameA
)(HANDLE
,LPSTR
,DWORD
);
75 static HANDLE (WINAPI
*pCreateJobObjectW
)(LPSECURITY_ATTRIBUTES sa
, LPCWSTR name
);
76 static BOOL (WINAPI
*pAssignProcessToJobObject
)(HANDLE job
, HANDLE process
);
77 static BOOL (WINAPI
*pIsProcessInJob
)(HANDLE process
, HANDLE job
, PBOOL result
);
78 static BOOL (WINAPI
*pTerminateJobObject
)(HANDLE job
, UINT exit_code
);
79 static BOOL (WINAPI
*pQueryInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
, LPDWORD ret_len
);
80 static BOOL (WINAPI
*pSetInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
);
81 static HANDLE (WINAPI
*pCreateIoCompletionPort
)(HANDLE file
, HANDLE existing_port
, ULONG_PTR key
, DWORD threads
);
82 static BOOL (WINAPI
*pGetNumaProcessorNode
)(UCHAR
, PUCHAR
);
83 static NTSTATUS (WINAPI
*pNtQueryInformationProcess
)(HANDLE
, PROCESSINFOCLASS
, PVOID
, ULONG
, PULONG
);
84 static BOOL (WINAPI
*pProcessIdToSessionId
)(DWORD
,DWORD
*);
85 static DWORD (WINAPI
*pWTSGetActiveConsoleSessionId
)(void);
86 static HANDLE (WINAPI
*pCreateToolhelp32Snapshot
)(DWORD
, DWORD
);
87 static BOOL (WINAPI
*pProcess32First
)(HANDLE
, PROCESSENTRY32
*);
88 static BOOL (WINAPI
*pProcess32Next
)(HANDLE
, PROCESSENTRY32
*);
89 static BOOL (WINAPI
*pThread32First
)(HANDLE
, THREADENTRY32
*);
90 static BOOL (WINAPI
*pThread32Next
)(HANDLE
, THREADENTRY32
*);
91 static BOOL (WINAPI
*pGetLogicalProcessorInformationEx
)(LOGICAL_PROCESSOR_RELATIONSHIP
,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*,DWORD
*);
92 static SIZE_T (WINAPI
*pGetLargePageMinimum
)(void);
93 static BOOL (WINAPI
*pInitializeProcThreadAttributeList
)(struct _PROC_THREAD_ATTRIBUTE_LIST
*, DWORD
, DWORD
, SIZE_T
*);
94 static BOOL (WINAPI
*pUpdateProcThreadAttribute
)(struct _PROC_THREAD_ATTRIBUTE_LIST
*, DWORD
, DWORD_PTR
, void *,SIZE_T
,void*,SIZE_T
*);
95 static void (WINAPI
*pDeleteProcThreadAttributeList
)(struct _PROC_THREAD_ATTRIBUTE_LIST
*);
96 static DWORD (WINAPI
*pGetActiveProcessorCount
)(WORD
);
98 /* ############################### */
99 static char base
[MAX_PATH
];
100 static char selfname
[MAX_PATH
];
101 static char* exename
;
102 static char resfile
[MAX_PATH
];
105 static char** myARGV
;
107 /* As some environment variables get very long on Unix, we only test for
108 * the first 127 bytes.
109 * Note that increasing this value past 256 may exceed the buffer size
110 * limitations of the *Profile functions (at least on Wine).
112 #define MAX_LISTED_ENV_VAR 128
114 /* ---------------- portable memory allocation thingie */
116 static char memory
[1024*256];
117 static char* memory_index
= memory
;
119 static char* grab_memory(size_t len
)
121 char* ret
= memory_index
;
123 len
= (len
+ 3) & ~3;
125 assert(memory_index
<= memory
+ sizeof(memory
));
129 static void release_memory(void)
131 memory_index
= memory
;
134 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
136 static const char* encodeA(const char* str
)
142 len
= strlen(str
) + 1;
143 ptr
= grab_memory(len
* 2 + 1);
144 for (i
= 0; i
< len
; i
++)
145 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
150 static const char* encodeW(const WCHAR
* str
)
156 len
= lstrlenW(str
) + 1;
157 ptr
= grab_memory(len
* 4 + 1);
159 for (i
= 0; i
< len
; i
++)
160 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
165 static unsigned decode_char(char c
)
167 if (c
>= '0' && c
<= '9') return c
- '0';
168 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
169 assert(c
>= 'A' && c
<= 'F');
173 static char* decodeA(const char* str
)
178 len
= strlen(str
) / 2;
179 if (!len
--) return NULL
;
180 ptr
= grab_memory(len
+ 1);
181 for (i
= 0; i
< len
; i
++)
182 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
187 /* This will be needed to decode Unicode strings saved by the child process
188 * when we test Unicode functions.
190 static WCHAR
* decodeW(const char* str
)
196 len
= strlen(str
) / 4;
197 if (!len
--) return NULL
;
198 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
199 for (i
= 0; i
< len
; i
++)
200 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
201 (decode_char(str
[4 * i
+ 1]) << 8) |
202 (decode_char(str
[4 * i
+ 2]) << 4) |
203 (decode_char(str
[4 * i
+ 3]) << 0);
208 /******************************************************************
211 * generates basic information like:
212 * base: absolute path to curr dir
213 * selfname: the way to reinvoke ourselves
214 * exename: executable without the path
215 * function-pointers, which are not implemented in all windows versions
217 static BOOL
init(void)
221 myARGC
= winetest_get_mainargs( &myARGV
);
222 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return FALSE
;
223 strcpy(selfname
, myARGV
[0]);
225 /* Strip the path of selfname */
226 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
227 else exename
= selfname
;
229 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
231 hkernel32
= GetModuleHandleA("kernel32");
232 hntdll
= GetModuleHandleA("ntdll.dll");
234 pNtQueryInformationProcess
= (void *)GetProcAddress(hntdll
, "NtQueryInformationProcess");
236 pGetNativeSystemInfo
= (void *) GetProcAddress(hkernel32
, "GetNativeSystemInfo");
237 pGetSystemRegistryQuota
= (void *) GetProcAddress(hkernel32
, "GetSystemRegistryQuota");
238 pIsWow64Process
= (void *) GetProcAddress(hkernel32
, "IsWow64Process");
239 pVirtualAllocEx
= (void *) GetProcAddress(hkernel32
, "VirtualAllocEx");
240 pVirtualFreeEx
= (void *) GetProcAddress(hkernel32
, "VirtualFreeEx");
241 pQueryFullProcessImageNameA
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameA");
242 pQueryFullProcessImageNameW
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameW");
243 pK32GetProcessImageFileNameA
= (void *) GetProcAddress(hkernel32
, "K32GetProcessImageFileNameA");
244 pCreateJobObjectW
= (void *)GetProcAddress(hkernel32
, "CreateJobObjectW");
245 pAssignProcessToJobObject
= (void *)GetProcAddress(hkernel32
, "AssignProcessToJobObject");
246 pIsProcessInJob
= (void *)GetProcAddress(hkernel32
, "IsProcessInJob");
247 pTerminateJobObject
= (void *)GetProcAddress(hkernel32
, "TerminateJobObject");
248 pQueryInformationJobObject
= (void *)GetProcAddress(hkernel32
, "QueryInformationJobObject");
249 pSetInformationJobObject
= (void *)GetProcAddress(hkernel32
, "SetInformationJobObject");
250 pCreateIoCompletionPort
= (void *)GetProcAddress(hkernel32
, "CreateIoCompletionPort");
251 pGetNumaProcessorNode
= (void *)GetProcAddress(hkernel32
, "GetNumaProcessorNode");
252 pProcessIdToSessionId
= (void *)GetProcAddress(hkernel32
, "ProcessIdToSessionId");
253 pWTSGetActiveConsoleSessionId
= (void *)GetProcAddress(hkernel32
, "WTSGetActiveConsoleSessionId");
254 pCreateToolhelp32Snapshot
= (void *)GetProcAddress(hkernel32
, "CreateToolhelp32Snapshot");
255 pProcess32First
= (void *)GetProcAddress(hkernel32
, "Process32First");
256 pProcess32Next
= (void *)GetProcAddress(hkernel32
, "Process32Next");
257 pThread32First
= (void *)GetProcAddress(hkernel32
, "Thread32First");
258 pThread32Next
= (void *)GetProcAddress(hkernel32
, "Thread32Next");
259 pGetLogicalProcessorInformationEx
= (void *)GetProcAddress(hkernel32
, "GetLogicalProcessorInformationEx");
260 pGetLargePageMinimum
= (void *)GetProcAddress(hkernel32
, "GetLargePageMinimum");
261 pInitializeProcThreadAttributeList
= (void *)GetProcAddress(hkernel32
, "InitializeProcThreadAttributeList");
262 pUpdateProcThreadAttribute
= (void *)GetProcAddress(hkernel32
, "UpdateProcThreadAttribute");
263 pDeleteProcThreadAttributeList
= (void *)GetProcAddress(hkernel32
, "DeleteProcThreadAttributeList");
264 pGetActiveProcessorCount
= (void *)GetProcAddress(hkernel32
, "GetActiveProcessorCount");
269 /******************************************************************
272 * generates an absolute file_name for temporary file
275 static void get_file_name(char* buf
)
280 GetTempPathA(sizeof(path
), path
);
281 GetTempFileNameA(path
, "wt", 0, buf
);
284 /******************************************************************
285 * static void childPrintf
288 static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h
, const char* fmt
, ...)
291 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
294 va_start(valist
, fmt
);
295 vsprintf(buffer
, fmt
, valist
);
297 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
301 /******************************************************************
304 * output most of the information in the child process
306 static void doChild(const char* file
, const char* option
)
308 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
312 char *ptrA
, *ptrA_save
;
313 WCHAR
*ptrW
, *ptrW_save
;
315 WCHAR bufW
[MAX_PATH
];
316 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
321 if (hFile
== INVALID_HANDLE_VALUE
) return;
323 /* output of startup info (Ansi) */
324 GetStartupInfoA(&siA
);
326 "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
327 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
328 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
329 "dwFlags=%u\nwShowWindow=%u\n"
330 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
331 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
332 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
333 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
334 siA
.dwFlags
, siA
.wShowWindow
,
335 (DWORD_PTR
)siA
.hStdInput
, (DWORD_PTR
)siA
.hStdOutput
, (DWORD_PTR
)siA
.hStdError
);
337 /* check the console handles in the TEB */
338 childPrintf(hFile
, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
339 (DWORD_PTR
)params
->hStdInput
, (DWORD_PTR
)params
->hStdOutput
,
340 (DWORD_PTR
)params
->hStdError
);
342 /* since GetStartupInfoW is only implemented in win2k,
343 * zero out before calling so we can notice the difference
345 memset(&siW
, 0, sizeof(siW
));
346 GetStartupInfoW(&siW
);
348 "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
349 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
350 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
351 "dwFlags=%u\nwShowWindow=%u\n"
352 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
353 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
354 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
355 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
356 siW
.dwFlags
, siW
.wShowWindow
,
357 (DWORD_PTR
)siW
.hStdInput
, (DWORD_PTR
)siW
.hStdOutput
, (DWORD_PTR
)siW
.hStdError
);
360 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
361 for (i
= 0; i
< myARGC
; i
++)
363 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
365 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
366 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
368 /* output toolhelp information */
369 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
370 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
371 memset(&pe
, 0, sizeof(pe
));
372 pe
.dwSize
= sizeof(pe
);
373 if (pProcess32First(snapshot
, &pe
))
375 while (pe
.th32ProcessID
!= GetCurrentProcessId())
376 if (!pProcess32Next(snapshot
, &pe
)) break;
378 CloseHandle(snapshot
);
379 ok(pe
.th32ProcessID
== GetCurrentProcessId(), "failed to find current process in snapshot\n");
381 "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n"
382 "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n"
383 "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n",
384 pe
.cntUsage
, pe
.th32DefaultHeapID
, pe
.th32ModuleID
,
385 pe
.cntThreads
, pe
.th32ParentProcessID
, pe
.pcPriClassBase
,
386 pe
.dwFlags
, encodeA(pe
.szExeFile
));
388 /* output of environment (Ansi) */
389 ptrA_save
= ptrA
= GetEnvironmentStringsA();
392 char env_var
[MAX_LISTED_ENV_VAR
];
394 childPrintf(hFile
, "[EnvironmentA]\n");
398 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
399 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
401 ptrA
+= strlen(ptrA
) + 1;
403 childPrintf(hFile
, "len=%d\n\n", i
);
404 FreeEnvironmentStringsA(ptrA_save
);
407 /* output of environment (Unicode) */
408 ptrW_save
= ptrW
= GetEnvironmentStringsW();
411 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
413 childPrintf(hFile
, "[EnvironmentW]\n");
417 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
418 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
419 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
421 ptrW
+= lstrlenW(ptrW
) + 1;
423 childPrintf(hFile
, "len=%d\n\n", i
);
424 FreeEnvironmentStringsW(ptrW_save
);
427 childPrintf(hFile
, "[Misc]\n");
428 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
429 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
430 if (GetCurrentDirectoryW(sizeof(bufW
) / sizeof(bufW
[0]), bufW
))
431 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
432 childPrintf(hFile
, "\n");
434 if (option
&& strcmp(option
, "console") == 0)
436 CONSOLE_SCREEN_BUFFER_INFO sbi
;
437 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
438 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
439 DWORD modeIn
, modeOut
;
441 childPrintf(hFile
, "[Console]\n");
442 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
444 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
445 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
446 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
447 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
448 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
449 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
451 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
452 GetConsoleCP(), GetConsoleOutputCP());
453 if (GetConsoleMode(hConIn
, &modeIn
))
454 childPrintf(hFile
, "InputMode=%u\n", modeIn
);
455 if (GetConsoleMode(hConOut
, &modeOut
))
456 childPrintf(hFile
, "OutputMode=%u\n", modeOut
);
458 /* now that we have written all relevant information, let's change it */
459 SetLastError(0xdeadbeef);
460 ret
= SetConsoleCP(1252);
461 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
463 win_skip("Setting the codepage is not implemented\n");
467 ok(ret
, "Setting CP\n");
468 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
471 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
472 ok( ret
, "Setting mode (%d)\n", GetLastError());
473 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
474 ok( ret
, "Setting mode (%d)\n", GetLastError());
475 sbi
.dwCursorPosition
.X
^= 1;
476 sbi
.dwCursorPosition
.Y
^= 1;
477 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
478 ok( ret
, "Setting cursor position (%d)\n", GetLastError());
480 if (option
&& strcmp(option
, "stdhandle") == 0)
482 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
483 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
485 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
490 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
491 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
492 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
496 if (option
&& strcmp(option
, "exit_code") == 0)
498 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
506 static char* getChildString(const char* sect
, const char* key
)
508 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
511 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
512 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
513 assert(!(strlen(buf
) & 1));
518 static WCHAR
* getChildStringW(const char* sect
, const char* key
)
520 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
523 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
524 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
525 assert(!(strlen(buf
) & 1));
530 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
531 * others... (windows uses stricmp while Un*x uses strcasecmp...)
533 static int wtstrcasecmp(const char* p1
, const char* p2
)
538 while (c1
== c2
&& c1
)
540 c1
= *p1
++; c2
= *p2
++;
543 c1
= toupper(c1
); c2
= toupper(c2
);
549 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
551 if (!s1
&& !s2
) return 0;
554 return (sensitive
) ? strcmp(s1
, s2
) : wtstrcasecmp(s1
, s2
);
557 static void ok_child_string( int line
, const char *sect
, const char *key
,
558 const char *expect
, int sensitive
)
560 char* result
= getChildString( sect
, key
);
561 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
562 sect
, key
, expect
? expect
: "(null)", result
);
565 static void ok_child_stringWA( int line
, const char *sect
, const char *key
,
566 const char *expect
, int sensitive
)
571 WCHAR
* result
= getChildStringW( sect
, key
);
573 len
= MultiByteToWideChar( CP_ACP
, 0, expect
, -1, NULL
, 0);
574 expectW
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
575 MultiByteToWideChar( CP_ACP
, 0, expect
, -1, expectW
, len
);
577 len
= WideCharToMultiByte( CP_ACP
, 0, result
, -1, NULL
, 0, NULL
, NULL
);
578 resultA
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(CHAR
));
579 WideCharToMultiByte( CP_ACP
, 0, result
, -1, resultA
, len
, NULL
, NULL
);
582 ok_(__FILE__
, line
)( lstrcmpW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
583 sect
, key
, expect
? expect
: "(null)", resultA
);
585 ok_(__FILE__
, line
)( lstrcmpiW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
586 sect
, key
, expect
? expect
: "(null)", resultA
);
587 HeapFree(GetProcessHeap(),0,expectW
);
588 HeapFree(GetProcessHeap(),0,resultA
);
591 static void ok_child_int( int line
, const char *sect
, const char *key
, UINT expect
)
593 UINT result
= GetPrivateProfileIntA( sect
, key
, !expect
, resfile
);
594 ok_(__FILE__
, line
)( result
== expect
, "%s:%s expected %u, but got %u\n", sect
, key
, expect
, result
);
597 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
598 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
599 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
600 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
602 static void test_Startup(void)
604 char buffer
[MAX_PATH
];
605 PROCESS_INFORMATION info
;
606 STARTUPINFOA startup
,si
;
608 static CHAR title
[] = "I'm the title string",
609 desktop
[] = "winsta0\\default",
612 /* let's start simplistic */
613 memset(&startup
, 0, sizeof(startup
));
614 startup
.cb
= sizeof(startup
);
615 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
616 startup
.wShowWindow
= SW_SHOWNORMAL
;
618 get_file_name(resfile
);
619 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
620 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
621 /* wait for child to terminate */
622 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
623 /* child process has changed result file, so let profile functions know about it */
624 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
625 CloseHandle(info
.hThread
);
626 CloseHandle(info
.hProcess
);
628 GetStartupInfoA(&si
);
629 okChildInt("StartupInfoA", "cb", startup
.cb
);
630 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
631 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
632 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
633 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
634 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
635 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
636 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
637 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
638 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
639 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
641 DeleteFileA(resfile
);
643 /* not so simplistic now */
644 memset(&startup
, 0, sizeof(startup
));
645 startup
.cb
= sizeof(startup
);
646 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
647 startup
.wShowWindow
= SW_SHOWNORMAL
;
648 startup
.lpTitle
= title
;
649 startup
.lpDesktop
= desktop
;
650 startup
.dwXCountChars
= 0x12121212;
651 startup
.dwYCountChars
= 0x23232323;
652 startup
.dwX
= 0x34343434;
653 startup
.dwY
= 0x45454545;
654 startup
.dwXSize
= 0x56565656;
655 startup
.dwYSize
= 0x67676767;
656 startup
.dwFillAttribute
= 0xA55A;
658 get_file_name(resfile
);
659 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
660 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
661 /* wait for child to terminate */
662 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
663 /* child process has changed result file, so let profile functions know about it */
664 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
665 CloseHandle(info
.hThread
);
666 CloseHandle(info
.hProcess
);
668 okChildInt("StartupInfoA", "cb", startup
.cb
);
669 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
670 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
671 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
672 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
673 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
674 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
675 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
676 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
677 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
678 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
679 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
681 DeleteFileA(resfile
);
683 /* not so simplistic now */
684 memset(&startup
, 0, sizeof(startup
));
685 startup
.cb
= sizeof(startup
);
686 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
687 startup
.wShowWindow
= SW_SHOWNORMAL
;
688 startup
.lpTitle
= title
;
689 startup
.lpDesktop
= NULL
;
690 startup
.dwXCountChars
= 0x12121212;
691 startup
.dwYCountChars
= 0x23232323;
692 startup
.dwX
= 0x34343434;
693 startup
.dwY
= 0x45454545;
694 startup
.dwXSize
= 0x56565656;
695 startup
.dwYSize
= 0x67676767;
696 startup
.dwFillAttribute
= 0xA55A;
698 get_file_name(resfile
);
699 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
700 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
701 /* wait for child to terminate */
702 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
703 /* child process has changed result file, so let profile functions know about it */
704 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
705 CloseHandle(info
.hThread
);
706 CloseHandle(info
.hProcess
);
708 okChildInt("StartupInfoA", "cb", startup
.cb
);
709 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
710 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
711 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
712 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
713 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
714 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
715 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
716 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
717 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
718 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
719 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
721 DeleteFileA(resfile
);
723 /* not so simplistic now */
724 memset(&startup
, 0, sizeof(startup
));
725 startup
.cb
= sizeof(startup
);
726 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
727 startup
.wShowWindow
= SW_SHOWNORMAL
;
728 startup
.lpTitle
= title
;
729 startup
.lpDesktop
= empty
;
730 startup
.dwXCountChars
= 0x12121212;
731 startup
.dwYCountChars
= 0x23232323;
732 startup
.dwX
= 0x34343434;
733 startup
.dwY
= 0x45454545;
734 startup
.dwXSize
= 0x56565656;
735 startup
.dwYSize
= 0x67676767;
736 startup
.dwFillAttribute
= 0xA55A;
738 get_file_name(resfile
);
739 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
740 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
741 /* wait for child to terminate */
742 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
743 /* child process has changed result file, so let profile functions know about it */
744 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
745 CloseHandle(info
.hThread
);
746 CloseHandle(info
.hProcess
);
748 okChildInt("StartupInfoA", "cb", startup
.cb
);
749 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
750 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
751 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
752 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
753 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
754 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
755 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
756 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
757 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
758 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
759 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
761 DeleteFileA(resfile
);
763 /* not so simplistic now */
764 memset(&startup
, 0, sizeof(startup
));
765 startup
.cb
= sizeof(startup
);
766 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
767 startup
.wShowWindow
= SW_SHOWNORMAL
;
768 startup
.lpTitle
= NULL
;
769 startup
.lpDesktop
= desktop
;
770 startup
.dwXCountChars
= 0x12121212;
771 startup
.dwYCountChars
= 0x23232323;
772 startup
.dwX
= 0x34343434;
773 startup
.dwY
= 0x45454545;
774 startup
.dwXSize
= 0x56565656;
775 startup
.dwYSize
= 0x67676767;
776 startup
.dwFillAttribute
= 0xA55A;
778 get_file_name(resfile
);
779 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
780 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
781 /* wait for child to terminate */
782 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
783 /* child process has changed result file, so let profile functions know about it */
784 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
785 CloseHandle(info
.hThread
);
786 CloseHandle(info
.hProcess
);
788 okChildInt("StartupInfoA", "cb", startup
.cb
);
789 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
790 result
= getChildString( "StartupInfoA", "lpTitle" );
791 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
792 "expected '%s' or null, got '%s'\n", selfname
, result
);
793 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
794 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
795 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
796 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
797 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
798 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
799 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
800 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
801 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
803 DeleteFileA(resfile
);
805 /* not so simplistic now */
806 memset(&startup
, 0, sizeof(startup
));
807 startup
.cb
= sizeof(startup
);
808 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
809 startup
.wShowWindow
= SW_SHOWNORMAL
;
810 startup
.lpTitle
= empty
;
811 startup
.lpDesktop
= desktop
;
812 startup
.dwXCountChars
= 0x12121212;
813 startup
.dwYCountChars
= 0x23232323;
814 startup
.dwX
= 0x34343434;
815 startup
.dwY
= 0x45454545;
816 startup
.dwXSize
= 0x56565656;
817 startup
.dwYSize
= 0x67676767;
818 startup
.dwFillAttribute
= 0xA55A;
820 get_file_name(resfile
);
821 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
822 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
823 /* wait for child to terminate */
824 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
825 /* child process has changed result file, so let profile functions know about it */
826 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
827 CloseHandle(info
.hThread
);
828 CloseHandle(info
.hProcess
);
830 okChildInt("StartupInfoA", "cb", startup
.cb
);
831 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
832 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
833 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
834 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
835 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
836 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
837 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
838 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
839 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
840 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
841 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
843 DeleteFileA(resfile
);
845 /* not so simplistic now */
846 memset(&startup
, 0, sizeof(startup
));
847 startup
.cb
= sizeof(startup
);
848 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
849 startup
.wShowWindow
= SW_SHOWNORMAL
;
850 startup
.lpTitle
= empty
;
851 startup
.lpDesktop
= empty
;
852 startup
.dwXCountChars
= 0x12121212;
853 startup
.dwYCountChars
= 0x23232323;
854 startup
.dwX
= 0x34343434;
855 startup
.dwY
= 0x45454545;
856 startup
.dwXSize
= 0x56565656;
857 startup
.dwYSize
= 0x67676767;
858 startup
.dwFillAttribute
= 0xA55A;
860 get_file_name(resfile
);
861 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
862 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
863 /* wait for child to terminate */
864 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
865 /* child process has changed result file, so let profile functions know about it */
866 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
867 CloseHandle(info
.hThread
);
868 CloseHandle(info
.hProcess
);
870 okChildInt("StartupInfoA", "cb", startup
.cb
);
871 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
872 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
873 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
874 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
875 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
876 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
877 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
878 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
879 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
880 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
881 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
883 DeleteFileA(resfile
);
885 /* TODO: test for A/W and W/A and W/W */
888 static void test_CommandLine(void)
890 char buffer
[MAX_PATH
], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
891 char buffer2
[MAX_PATH
];
892 PROCESS_INFORMATION info
;
893 STARTUPINFOA startup
;
896 memset(&startup
, 0, sizeof(startup
));
897 startup
.cb
= sizeof(startup
);
898 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
899 startup
.wShowWindow
= SW_SHOWNORMAL
;
902 get_file_name(resfile
);
903 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
904 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
905 /* wait for child to terminate */
906 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
907 /* child process has changed result file, so let profile functions know about it */
908 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
909 CloseHandle(info
.hThread
);
910 CloseHandle(info
.hProcess
);
912 okChildInt("Arguments", "argcA", 5);
913 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
914 okChildString("Arguments", "argvA5", NULL
);
915 okChildString("Arguments", "CommandLineA", buffer
);
917 DeleteFileA(resfile
);
919 memset(&startup
, 0, sizeof(startup
));
920 startup
.cb
= sizeof(startup
);
921 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
922 startup
.wShowWindow
= SW_SHOWNORMAL
;
925 get_file_name(resfile
);
926 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname
, resfile
);
927 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
928 /* wait for child to terminate */
929 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
930 /* child process has changed result file, so let profile functions know about it */
931 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
932 CloseHandle(info
.hThread
);
933 CloseHandle(info
.hProcess
);
935 okChildInt("Arguments", "argcA", 7);
936 okChildString("Arguments", "argvA4", "a\"b\\");
937 okChildString("Arguments", "argvA5", "c\"");
938 okChildString("Arguments", "argvA6", "d");
939 okChildString("Arguments", "argvA7", NULL
);
940 okChildString("Arguments", "CommandLineA", buffer
);
942 DeleteFileA(resfile
);
944 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
945 get_file_name(resfile
);
946 /* Use exename to avoid buffer containing things like 'C:' */
947 sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
948 SetLastError(0xdeadbeef);
949 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
950 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
951 /* wait for child to terminate */
952 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
953 /* child process has changed result file, so let profile functions know about it */
954 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
955 CloseHandle(info
.hThread
);
956 CloseHandle(info
.hProcess
);
957 sprintf(buffer
, "./%s", exename
);
958 okChildString("Arguments", "argvA0", buffer
);
960 DeleteFileA(resfile
);
962 get_file_name(resfile
);
963 /* Use exename to avoid buffer containing things like 'C:' */
964 sprintf(buffer
, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
965 SetLastError(0xdeadbeef);
966 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
967 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
968 /* wait for child to terminate */
969 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
970 /* child process has changed result file, so let profile functions know about it */
971 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
972 CloseHandle(info
.hThread
);
973 CloseHandle(info
.hProcess
);
974 sprintf(buffer
, ".\\%s", exename
);
975 okChildString("Arguments", "argvA0", buffer
);
977 DeleteFileA(resfile
);
979 get_file_name(resfile
);
980 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
981 assert ( lpFilePart
!= 0);
982 *(lpFilePart
-1 ) = 0;
983 p
= strrchr(fullpath
, '\\');
984 /* Use exename to avoid buffer containing things like 'C:' */
985 if (p
) sprintf(buffer
, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p
, exename
, resfile
);
986 else sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
987 SetLastError(0xdeadbeef);
988 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
989 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
990 /* wait for child to terminate */
991 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
992 /* child process has changed result file, so let profile functions know about it */
993 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
994 CloseHandle(info
.hThread
);
995 CloseHandle(info
.hProcess
);
996 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
997 else sprintf(buffer
, "./%s", exename
);
998 okChildString("Arguments", "argvA0", buffer
);
1000 DeleteFileA(resfile
);
1003 get_file_name(resfile
);
1004 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
1005 assert ( lpFilePart
!= 0);
1006 *(lpFilePart
-1 ) = 0;
1007 p
= strrchr(fullpath
, '\\');
1008 /* Use exename to avoid buffer containing things like 'C:' */
1009 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
1010 else sprintf(buffer
, "./%s", exename
);
1011 sprintf(buffer2
, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile
);
1012 SetLastError(0xdeadbeef);
1013 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1014 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
1015 /* wait for child to terminate */
1016 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1017 /* child process has changed result file, so let profile functions know about it */
1018 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1019 CloseHandle(info
.hThread
);
1020 CloseHandle(info
.hProcess
);
1021 sprintf(buffer
, "tests/process.c dump %s", resfile
);
1022 okChildString("Arguments", "argvA0", "dummy");
1023 okChildString("Arguments", "CommandLineA", buffer2
);
1024 okChildStringWA("Arguments", "CommandLineW", buffer2
);
1026 DeleteFileA(resfile
);
1028 if (0) /* Test crashes on NT-based Windows. */
1030 /* Test NULL application name and command line parameters. */
1031 SetLastError(0xdeadbeef);
1032 ret
= CreateProcessA(NULL
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1033 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1034 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1035 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1040 /* Test empty application name parameter. */
1041 SetLastError(0xdeadbeef);
1042 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1043 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1044 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
1045 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
1046 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
1047 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1051 /* Test empty application name and command line parameters. */
1052 SetLastError(0xdeadbeef);
1053 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1054 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1055 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
1056 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
1057 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
1058 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1060 /* Test empty command line parameter. */
1061 SetLastError(0xdeadbeef);
1062 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1063 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1064 ok(GetLastError() == ERROR_FILE_NOT_FOUND
||
1065 GetLastError() == ERROR_PATH_NOT_FOUND
/* NT4 */ ||
1066 GetLastError() == ERROR_BAD_PATHNAME
/* Win98 */ ||
1067 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7 */,
1068 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1070 strcpy(buffer
, "doesnotexist.exe");
1071 strcpy(buffer2
, "does not exist.exe");
1073 /* Test nonexistent application name. */
1074 SetLastError(0xdeadbeef);
1075 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1076 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1077 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1079 SetLastError(0xdeadbeef);
1080 ret
= CreateProcessA(buffer2
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1081 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1082 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1084 /* Test nonexistent command line parameter. */
1085 SetLastError(0xdeadbeef);
1086 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1087 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1088 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1090 SetLastError(0xdeadbeef);
1091 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1092 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1093 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1096 static void test_Directory(void)
1098 char buffer
[MAX_PATH
];
1099 PROCESS_INFORMATION info
;
1100 STARTUPINFOA startup
;
1101 char windir
[MAX_PATH
];
1102 static CHAR cmdline
[] = "winver.exe";
1104 memset(&startup
, 0, sizeof(startup
));
1105 startup
.cb
= sizeof(startup
);
1106 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1107 startup
.wShowWindow
= SW_SHOWNORMAL
;
1110 get_file_name(resfile
);
1111 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1112 GetWindowsDirectoryA( windir
, sizeof(windir
) );
1113 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
1114 /* wait for child to terminate */
1115 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1116 /* child process has changed result file, so let profile functions know about it */
1117 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1118 CloseHandle(info
.hThread
);
1119 CloseHandle(info
.hProcess
);
1121 okChildIString("Misc", "CurrDirA", windir
);
1123 DeleteFileA(resfile
);
1125 /* search PATH for the exe if directory is NULL */
1126 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1127 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
1128 CloseHandle(info
.hThread
);
1129 CloseHandle(info
.hProcess
);
1131 /* if any directory is provided, don't search PATH, error on bad directory */
1132 SetLastError(0xdeadbeef);
1133 memset(&info
, 0, sizeof(info
));
1134 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
1135 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
1136 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1137 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
1140 static void test_Toolhelp(void)
1142 char buffer
[MAX_PATH
];
1143 STARTUPINFOA startup
;
1144 PROCESS_INFORMATION info
;
1145 HANDLE process
, thread
, snapshot
;
1151 #if defined(__REACTOS__) && defined(_M_AMD64)
1152 if (!winetest_interactive
)
1154 skip("ROSTESTS-372: Skipping test in kernel32_winetest:process test_Toolhelp because it leaves a process behind on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
1159 memset(&startup
, 0, sizeof(startup
));
1160 startup
.cb
= sizeof(startup
);
1161 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1162 startup
.wShowWindow
= SW_SHOWNORMAL
;
1164 get_file_name(resfile
);
1165 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1166 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1167 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1168 CloseHandle(info
.hProcess
);
1169 CloseHandle(info
.hThread
);
1171 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1172 okChildInt("Toolhelp", "cntUsage", 0);
1173 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1174 okChildInt("Toolhelp", "th32ModuleID", 0);
1175 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1176 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1177 okChildInt("Toolhelp", "dwFlags", 0);
1180 DeleteFileA(resfile
);
1182 #if defined(__REACTOS__) && defined(_M_AMD64)
1183 if (!winetest_interactive
)
1185 skip("ROSTESTS-371: Skipping kernel32_winetest:sync test_apc_deadlock because it fails on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
1191 get_file_name(resfile
);
1192 sprintf(buffer
, "\"%s\" tests/process.c nested \"%s\"", selfname
, resfile
);
1193 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1194 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1196 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1197 ok(process
!= NULL
, "OpenProcess failed %u\n", GetLastError());
1198 CloseHandle(process
);
1200 CloseHandle(info
.hProcess
);
1201 CloseHandle(info
.hThread
);
1202 #if defined(__REACTOS__) && defined(_M_AMD64)
1206 for (i
= 0; i
< 20; i
++)
1208 SetLastError(0xdeadbeef);
1209 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1210 ok(process
|| GetLastError() == ERROR_INVALID_PARAMETER
, "OpenProcess failed %u\n", GetLastError());
1211 if (!process
) break;
1212 CloseHandle(process
);
1215 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1216 ok(i
< 20 || broken(i
== 20), "process object not released\n");
1218 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
1219 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1220 memset(&pe
, 0, sizeof(pe
));
1221 pe
.dwSize
= sizeof(pe
);
1222 if (pProcess32First(snapshot
, &pe
))
1224 while (pe
.th32ParentProcessID
!= info
.dwProcessId
)
1225 if (!pProcess32Next(snapshot
, &pe
)) break;
1227 CloseHandle(snapshot
);
1228 ok(pe
.th32ParentProcessID
== info
.dwProcessId
, "failed to find nested child process\n");
1230 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, pe
.th32ProcessID
);
1231 ok(process
!= NULL
, "OpenProcess failed %u\n", GetLastError());
1233 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD
, 0);
1234 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1235 memset(&te
, 0, sizeof(te
));
1236 te
.dwSize
= sizeof(te
);
1237 if (pThread32First(snapshot
, &te
))
1239 while (te
.th32OwnerProcessID
!= pe
.th32ProcessID
)
1240 if (!pThread32Next(snapshot
, &te
)) break;
1242 CloseHandle(snapshot
);
1243 ok(te
.th32OwnerProcessID
== pe
.th32ProcessID
, "failed to find suspended thread\n");
1245 thread
= OpenThread(THREAD_ALL_ACCESS_NT4
, FALSE
, te
.th32ThreadID
);
1246 ok(thread
!= NULL
, "OpenThread failed %u\n", GetLastError());
1247 ret
= ResumeThread(thread
);
1248 ok(ret
== 1, "expected 1, got %u\n", ret
);
1249 CloseHandle(thread
);
1251 ok(WaitForSingleObject(process
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1252 CloseHandle(process
);
1254 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1255 okChildInt("Toolhelp", "cntUsage", 0);
1256 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1257 okChildInt("Toolhelp", "th32ModuleID", 0);
1258 okChildInt("Toolhelp", "th32ParentProcessID", info
.dwProcessId
);
1259 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1260 okChildInt("Toolhelp", "dwFlags", 0);
1263 DeleteFileA(resfile
);
1266 static BOOL
is_str_env_drive_dir(const char* str
)
1268 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1269 str
[3] == '=' && str
[4] == str
[1];
1272 /* compared expected child's environment (in gesA) from actual
1273 * environment our child got
1275 static void cmpEnvironment(const char* gesA
)
1283 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1285 /* now look each parent env in child */
1286 if ((ptrA
= gesA
) != NULL
)
1290 for (i
= 0; i
< clen
; i
++)
1292 sprintf(key
, "env%d", i
);
1293 res
= getChildString("EnvironmentA", key
);
1294 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1298 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1300 ptrA
+= strlen(ptrA
) + 1;
1304 /* and each child env in parent */
1305 for (i
= 0; i
< clen
; i
++)
1307 sprintf(key
, "env%d", i
);
1308 res
= getChildString("EnvironmentA", key
);
1309 if ((ptrA
= gesA
) != NULL
)
1313 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1315 ptrA
+= strlen(ptrA
) + 1;
1317 if (!*ptrA
) ptrA
= NULL
;
1320 if (!is_str_env_drive_dir(res
))
1322 found
= ptrA
!= NULL
;
1323 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1325 /* else => should also test we get the right per drive default directory here... */
1329 static void test_Environment(void)
1331 char buffer
[MAX_PATH
];
1332 PROCESS_INFORMATION info
;
1333 STARTUPINFOA startup
;
1341 memset(&startup
, 0, sizeof(startup
));
1342 startup
.cb
= sizeof(startup
);
1343 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1344 startup
.wShowWindow
= SW_SHOWNORMAL
;
1347 get_file_name(resfile
);
1348 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1349 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1350 /* wait for child to terminate */
1351 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1352 /* child process has changed result file, so let profile functions know about it */
1353 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1355 env
= GetEnvironmentStringsA();
1356 cmpEnvironment(env
);
1358 DeleteFileA(resfile
);
1360 memset(&startup
, 0, sizeof(startup
));
1361 startup
.cb
= sizeof(startup
);
1362 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1363 startup
.wShowWindow
= SW_SHOWNORMAL
;
1366 get_file_name(resfile
);
1367 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1373 slen
= strlen(ptr
)+1;
1374 child_env_len
+= slen
;
1377 /* Add space for additional environment variables */
1378 child_env_len
+= 256;
1379 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1382 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1383 ptr
+= strlen(ptr
) + 1;
1384 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1385 ptr
+= strlen(ptr
) + 1;
1386 strcpy(ptr
, "FOO=BAR");
1387 ptr
+= strlen(ptr
) + 1;
1388 strcpy(ptr
, "BAR=FOOBAR");
1389 ptr
+= strlen(ptr
) + 1;
1390 /* copy all existing variables except:
1392 * - PATH (already set above)
1393 * - the directory definitions (=[A-Z]:=)
1395 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1397 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1398 strncmp(ptr2
, "WINELOADER=", 11) != 0 &&
1399 !is_str_env_drive_dir(ptr2
))
1402 ptr
+= strlen(ptr
) + 1;
1406 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1407 /* wait for child to terminate */
1408 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1409 /* child process has changed result file, so let profile functions know about it */
1410 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1412 cmpEnvironment(child_env
);
1414 HeapFree(GetProcessHeap(), 0, child_env
);
1415 FreeEnvironmentStringsA(env
);
1417 DeleteFileA(resfile
);
1420 static void test_SuspendFlag(void)
1422 char buffer
[MAX_PATH
];
1423 PROCESS_INFORMATION info
;
1424 STARTUPINFOA startup
, us
;
1428 /* let's start simplistic */
1429 memset(&startup
, 0, sizeof(startup
));
1430 startup
.cb
= sizeof(startup
);
1431 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1432 startup
.wShowWindow
= SW_SHOWNORMAL
;
1434 get_file_name(resfile
);
1435 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1436 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1438 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1440 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1441 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1443 /* wait for child to terminate */
1444 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1445 /* child process has changed result file, so let profile functions know about it */
1446 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1448 GetStartupInfoA(&us
);
1450 okChildInt("StartupInfoA", "cb", startup
.cb
);
1451 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1452 result
= getChildString( "StartupInfoA", "lpTitle" );
1453 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1454 "expected '%s' or null, got '%s'\n", selfname
, result
);
1455 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1456 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1457 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1458 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1459 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1460 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1461 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1462 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1463 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1465 DeleteFileA(resfile
);
1468 static void test_DebuggingFlag(void)
1470 char buffer
[MAX_PATH
];
1471 void *processbase
= NULL
;
1472 PROCESS_INFORMATION info
;
1473 STARTUPINFOA startup
, us
;
1478 /* let's start simplistic */
1479 memset(&startup
, 0, sizeof(startup
));
1480 startup
.cb
= sizeof(startup
);
1481 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1482 startup
.wShowWindow
= SW_SHOWNORMAL
;
1484 get_file_name(resfile
);
1485 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1486 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1488 /* get all startup events up to the entry point break exception */
1491 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1492 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1495 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1496 "first event: %d\n", de
.dwDebugEventCode
);
1497 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1499 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1500 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1501 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1502 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1504 ok(dbg
, "I have seen a debug event\n");
1505 /* wait for child to terminate */
1506 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1507 /* child process has changed result file, so let profile functions know about it */
1508 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1510 GetStartupInfoA(&us
);
1512 okChildInt("StartupInfoA", "cb", startup
.cb
);
1513 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1514 result
= getChildString( "StartupInfoA", "lpTitle" );
1515 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1516 "expected '%s' or null, got '%s'\n", selfname
, result
);
1517 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1518 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1519 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1520 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1521 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1522 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1523 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1524 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1525 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1527 DeleteFileA(resfile
);
1530 static BOOL
is_console(HANDLE h
)
1532 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1535 static void test_Console(void)
1537 char buffer
[MAX_PATH
];
1538 PROCESS_INFORMATION info
;
1539 STARTUPINFOA startup
, us
;
1540 SECURITY_ATTRIBUTES sa
;
1541 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1542 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1543 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1545 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1546 const char* msg
= "This is a std-handle inheritance test.";
1548 BOOL run_tests
= TRUE
;
1551 memset(&startup
, 0, sizeof(startup
));
1552 startup
.cb
= sizeof(startup
);
1553 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1554 startup
.wShowWindow
= SW_SHOWNORMAL
;
1556 sa
.nLength
= sizeof(sa
);
1557 sa
.lpSecurityDescriptor
= NULL
;
1558 sa
.bInheritHandle
= TRUE
;
1560 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1561 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1563 /* first, we need to be sure we're attached to a console */
1564 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1566 /* we're not attached to a console, let's do it */
1568 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1569 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1571 /* now verify everything's ok */
1572 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1573 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1574 startup
.hStdError
= startup
.hStdOutput
;
1576 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1577 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
), "Getting console in mode\n");
1578 ok(GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console out mode\n");
1579 cpIn
= GetConsoleCP();
1580 cpOut
= GetConsoleOutputCP();
1582 get_file_name(resfile
);
1583 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" console", selfname
, resfile
);
1584 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1586 /* wait for child to terminate */
1587 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1588 /* child process has changed result file, so let profile functions know about it */
1589 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1591 /* now get the modification the child has made, and resets parents expected values */
1592 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1593 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
), "Getting console in mode\n");
1594 ok(GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console out mode\n");
1596 SetConsoleMode(startup
.hStdInput
, modeIn
);
1597 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1599 cpInC
= GetConsoleCP();
1600 cpOutC
= GetConsoleOutputCP();
1602 /* Try to set invalid CP */
1603 SetLastError(0xdeadbeef);
1604 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1605 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1606 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1607 "GetLastError: expecting %u got %u\n",
1608 ERROR_INVALID_PARAMETER
, GetLastError());
1609 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1613 SetLastError(0xdeadbeef);
1614 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1615 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1616 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1617 "GetLastError: expecting %u got %u\n",
1618 ERROR_INVALID_PARAMETER
, GetLastError());
1621 SetConsoleOutputCP(cpOut
);
1623 GetStartupInfoA(&us
);
1625 okChildInt("StartupInfoA", "cb", startup
.cb
);
1626 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1627 result
= getChildString( "StartupInfoA", "lpTitle" );
1628 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1629 "expected '%s' or null, got '%s'\n", selfname
, result
);
1630 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1631 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1632 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1633 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1634 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1635 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1636 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1637 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1638 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1640 /* check child correctly inherited the console */
1641 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1642 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1643 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1644 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1645 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1646 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1647 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1648 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1649 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1650 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1651 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1652 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1653 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1654 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1655 okChildInt("Console", "InputCP", cpIn
);
1656 okChildInt("Console", "OutputCP", cpOut
);
1657 okChildInt("Console", "InputMode", modeIn
);
1658 okChildInt("Console", "OutputMode", modeOut
);
1662 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1663 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1666 win_skip("Setting the codepage is not implemented\n");
1668 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1669 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1670 trace("cursor position(X): %d/%d\n",sbi
.dwCursorPosition
.X
, sbiC
.dwCursorPosition
.X
);
1671 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1674 DeleteFileA(resfile
);
1676 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1677 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1678 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1679 "Duplicating as inheritable child-output pipe\n");
1680 CloseHandle(hChildOut
);
1682 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1683 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1684 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1685 "Duplicating as inheritable child-input pipe\n");
1686 CloseHandle(hChildIn
);
1688 memset(&startup
, 0, sizeof(startup
));
1689 startup
.cb
= sizeof(startup
);
1690 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1691 startup
.wShowWindow
= SW_SHOWNORMAL
;
1692 startup
.hStdInput
= hChildInInh
;
1693 startup
.hStdOutput
= hChildOutInh
;
1694 startup
.hStdError
= hChildOutInh
;
1696 get_file_name(resfile
);
1697 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname
, resfile
);
1698 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1699 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1700 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1702 msg_len
= strlen(msg
) + 1;
1703 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1704 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1705 memset(buffer
, 0, sizeof(buffer
));
1706 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1707 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1709 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1710 ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
);
1712 /* wait for child to terminate */
1713 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1714 /* child process has changed result file, so let profile functions know about it */
1715 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1717 okChildString("StdHandle", "msg", msg
);
1720 DeleteFileA(resfile
);
1723 static void test_ExitCode(void)
1725 char buffer
[MAX_PATH
];
1726 PROCESS_INFORMATION info
;
1727 STARTUPINFOA startup
;
1730 /* let's start simplistic */
1731 memset(&startup
, 0, sizeof(startup
));
1732 startup
.cb
= sizeof(startup
);
1733 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1734 startup
.wShowWindow
= SW_SHOWNORMAL
;
1736 get_file_name(resfile
);
1737 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname
, resfile
);
1738 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1740 /* wait for child to terminate */
1741 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1742 /* child process has changed result file, so let profile functions know about it */
1743 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1745 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1746 okChildInt("ExitCode", "value", code
);
1749 DeleteFileA(resfile
);
1752 static void test_OpenProcess(void)
1756 MEMORY_BASIC_INFORMATION info
;
1757 SIZE_T dummy
, read_bytes
;
1760 /* not exported in all windows versions */
1761 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1762 win_skip("VirtualAllocEx not found\n");
1766 /* without PROCESS_VM_OPERATION */
1767 hproc
= OpenProcess(PROCESS_ALL_ACCESS_NT4
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1768 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1770 SetLastError(0xdeadbeef);
1771 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1772 ok(!addr1
, "VirtualAllocEx should fail\n");
1773 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1776 win_skip("VirtualAllocEx not implemented\n");
1779 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1781 read_bytes
= 0xdeadbeef;
1782 SetLastError(0xdeadbeef);
1783 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1784 ok(ret
, "ReadProcessMemory error %d\n", GetLastError());
1785 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1789 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1790 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1792 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1793 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1795 /* without PROCESS_QUERY_INFORMATION */
1796 SetLastError(0xdeadbeef);
1797 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1798 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1799 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1801 /* without PROCESS_VM_READ */
1802 read_bytes
= 0xdeadbeef;
1803 SetLastError(0xdeadbeef);
1804 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1805 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1806 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1807 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1811 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1813 memset(&info
, 0xcc, sizeof(info
));
1814 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1815 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1817 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1818 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1819 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1820 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1821 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1822 /* NT reports Protect == 0 for a not committed memory block */
1823 ok(info
.Protect
== 0 /* NT */ ||
1824 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1825 "%x != PAGE_NOACCESS\n", info
.Protect
);
1826 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1828 SetLastError(0xdeadbeef);
1829 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1830 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1831 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1835 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
1838 SetLastError(0xdeadbeef);
1839 memset(&info
, 0xcc, sizeof(info
));
1840 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1841 if (read_bytes
) /* win8 */
1843 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1844 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1845 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1846 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1847 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1848 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1849 ok(info
.Protect
== 0, "%x != PAGE_NOACCESS\n", info
.Protect
);
1850 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1852 else /* before win8 */
1853 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1855 SetLastError(0xdeadbeef);
1856 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1857 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1858 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1863 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1866 static void test_GetProcessVersion(void)
1868 static char cmdline
[] = "winver.exe";
1869 PROCESS_INFORMATION pi
;
1873 SetLastError(0xdeadbeef);
1874 ret
= GetProcessVersion(0);
1875 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1877 SetLastError(0xdeadbeef);
1878 ret
= GetProcessVersion(GetCurrentProcessId());
1879 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1881 memset(&si
, 0, sizeof(si
));
1883 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1884 si
.wShowWindow
= SW_HIDE
;
1885 SetLastError(0xdeadbeef);
1886 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1887 ok(ret
, "CreateProcess error %u\n", GetLastError());
1889 SetLastError(0xdeadbeef);
1890 ret
= GetProcessVersion(pi
.dwProcessId
);
1891 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1893 SetLastError(0xdeadbeef);
1894 ret
= TerminateProcess(pi
.hProcess
, 0);
1895 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1897 CloseHandle(pi
.hProcess
);
1898 CloseHandle(pi
.hThread
);
1901 static void test_GetProcessImageFileNameA(void)
1904 CHAR process
[MAX_PATH
];
1905 static const char harddisk
[] = "\\Device\\HarddiskVolume";
1907 if (!pK32GetProcessImageFileNameA
)
1909 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1913 /* callers must guess the buffer size */
1914 SetLastError(0xdeadbeef);
1915 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL
, 0);
1916 ok(!rc
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
1917 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc
, GetLastError());
1920 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), process
, sizeof(process
));
1921 expect_eq_d(rc
, lstrlenA(process
));
1922 if (strncmp(process
, harddisk
, lstrlenA(harddisk
)))
1924 todo_wine
win_skip("%s is probably on a network share, skipping tests\n", process
);
1928 if (!pQueryFullProcessImageNameA
)
1929 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1932 CHAR image
[MAX_PATH
];
1935 length
= sizeof(image
);
1936 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE
, image
, &length
));
1937 expect_eq_d(length
, lstrlenA(image
));
1938 ok(lstrcmpiA(process
, image
) == 0, "expected '%s' to be equal to '%s'\n", process
, image
);
1942 static void test_QueryFullProcessImageNameA(void)
1944 #define INIT_STR "Just some words"
1946 CHAR buf
[MAX_PATH
], module
[MAX_PATH
];
1948 if (!pQueryFullProcessImageNameA
)
1950 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1955 SetLastError(0); /* old Windows don't reset it on success */
1956 size
= GetModuleFileNameA(NULL
, module
, sizeof(module
));
1957 ok(size
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
, "GetModuleFileName failed: %u le=%u\n", size
, GetLastError());
1959 /* get the buffer length without \0 terminator */
1960 length
= sizeof(buf
);
1961 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1962 expect_eq_d(length
, lstrlenA(buf
));
1963 ok((buf
[0] == '\\' && buf
[1] == '\\') ||
1964 lstrcmpiA(buf
, module
) == 0, "expected %s to match %s\n", buf
, module
);
1966 /* when the buffer is too small
1967 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1968 * - the size variable is not modified
1969 * tested with the biggest too small size
1972 sprintf(buf
,INIT_STR
);
1973 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1974 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1975 expect_eq_d(length
, size
);
1976 expect_eq_s(INIT_STR
, buf
);
1978 /* retest with smaller buffer size
1981 sprintf(buf
,INIT_STR
);
1982 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1983 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1984 expect_eq_d(4, size
);
1985 expect_eq_s(INIT_STR
, buf
);
1987 /* this is a difference between the ascii and the unicode version
1988 * the unicode version crashes when the size is big enough to hold
1989 * the result while the ascii version throws an error
1992 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1993 expect_eq_d(1024, size
);
1994 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1997 static void test_QueryFullProcessImageNameW(void)
2000 WCHAR module_name
[1024], device
[1024];
2001 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
2005 if (!pQueryFullProcessImageNameW
)
2007 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
2011 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
2013 /* GetCurrentProcess pseudo-handle */
2014 size
= sizeof(buf
) / sizeof(buf
[0]);
2015 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
2016 expect_eq_d(lstrlenW(buf
), size
);
2017 expect_eq_ws_i(buf
, module_name
);
2019 hSelf
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
2021 size
= sizeof(buf
) / sizeof(buf
[0]);
2022 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
2023 expect_eq_d(lstrlenW(buf
), size
);
2024 expect_eq_ws_i(buf
, module_name
);
2026 /* Buffer too small */
2027 size
= lstrlenW(module_name
)/2;
2028 lstrcpyW(buf
, deviceW
);
2029 SetLastError(0xdeadbeef);
2030 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
2031 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
2032 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2033 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
2035 /* Too small - not space for NUL terminator */
2036 size
= lstrlenW(module_name
);
2037 SetLastError(0xdeadbeef);
2038 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
2039 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
2040 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2044 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
2045 expect_eq_d(0, size
);
2046 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2048 /* Buffer too small */
2049 size
= lstrlenW(module_name
)/2;
2050 SetLastError(0xdeadbeef);
2051 lstrcpyW(buf
, module_name
);
2052 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
2053 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
2054 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2055 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
2059 size
= sizeof(buf
) / sizeof(buf
[0]);
2060 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
2061 expect_eq_d(lstrlenW(buf
), size
);
2062 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
2063 ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
2065 module_name
[2] = '\0';
2067 size
= QueryDosDeviceW(module_name
, device
, sizeof(device
)/sizeof(device
[0]));
2068 ok(size
, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2069 len
= lstrlenW(device
);
2070 ok(size
>= len
+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size
, len
, wine_dbgstr_w(device
));
2072 if (size
>= lstrlenW(buf
))
2074 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2078 ok(buf
[len
] == '\\', "expected '%c' to be a '\\' in %s\n", buf
[len
], wine_dbgstr_w(module_name
));
2080 ok(lstrcmpiW(device
, buf
) == 0, "expected %s to match %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2081 ok(lstrcmpiW(module_name
+3, buf
+len
+1) == 0, "expected '%s' to match '%s'\n", wine_dbgstr_w(module_name
+3), wine_dbgstr_w(buf
+len
+1));
2087 static void test_Handles(void)
2089 HANDLE handle
= GetCurrentProcess();
2094 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
2095 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
2096 "invalid current process handle %p\n", handle
);
2097 ret
= GetExitCodeProcess( handle
, &code
);
2098 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
2100 /* truncated handle */
2101 SetLastError( 0xdeadbeef );
2102 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
2103 ret
= GetExitCodeProcess( handle
, &code
);
2104 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2105 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
2106 /* sign-extended handle */
2107 SetLastError( 0xdeadbeef );
2108 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
2109 ret
= GetExitCodeProcess( handle
, &code
);
2110 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
2111 /* invalid high-word */
2112 SetLastError( 0xdeadbeef );
2113 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
2114 ret
= GetExitCodeProcess( handle
, &code
);
2115 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2116 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
2119 handle
= GetStdHandle( STD_ERROR_HANDLE
);
2120 ok( handle
!= 0, "handle %p\n", handle
);
2121 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
2122 0, TRUE
, DUPLICATE_SAME_ACCESS
);
2123 SetStdHandle( STD_ERROR_HANDLE
, h3
);
2124 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
2125 h2
= GetStdHandle( STD_ERROR_HANDLE
);
2127 broken( h2
== h3
) || /* nt4, w2k */
2128 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
2129 "wrong handle %p/%p\n", h2
, h3
);
2130 SetStdHandle( STD_ERROR_HANDLE
, handle
);
2133 static void test_IsWow64Process(void)
2135 PROCESS_INFORMATION pi
;
2139 static char cmdline
[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2140 static char cmdline_wow64
[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2142 if (!pIsWow64Process
)
2144 skip("IsWow64Process is not available\n");
2148 memset(&si
, 0, sizeof(si
));
2150 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2151 si
.wShowWindow
= SW_HIDE
;
2152 ret
= CreateProcessA(NULL
, cmdline_wow64
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2155 trace("Created process %s\n", cmdline_wow64
);
2157 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2158 ok(ret
, "IsWow64Process failed.\n");
2159 ok(is_wow64
, "is_wow64 returned FALSE.\n");
2161 ret
= TerminateProcess(pi
.hProcess
, 0);
2162 ok(ret
, "TerminateProcess error\n");
2164 CloseHandle(pi
.hProcess
);
2165 CloseHandle(pi
.hThread
);
2168 memset(&si
, 0, sizeof(si
));
2170 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2171 si
.wShowWindow
= SW_HIDE
;
2172 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2175 trace("Created process %s\n", cmdline
);
2177 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2178 ok(ret
, "IsWow64Process failed.\n");
2179 ok(!is_wow64
, "is_wow64 returned TRUE.\n");
2181 ret
= TerminateProcess(pi
.hProcess
, 0);
2182 ok(ret
, "TerminateProcess error\n");
2184 CloseHandle(pi
.hProcess
);
2185 CloseHandle(pi
.hThread
);
2189 static void test_SystemInfo(void)
2191 SYSTEM_INFO si
, nsi
;
2194 if (!pGetNativeSystemInfo
)
2196 win_skip("GetNativeSystemInfo is not available\n");
2200 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
2203 pGetNativeSystemInfo(&nsi
);
2206 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
2208 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
2209 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2210 S(U(nsi
)).wProcessorArchitecture
);
2211 ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
,
2212 "Expected PROCESSOR_AMD_X8664, got %d\n",
2213 nsi
.dwProcessorType
);
2218 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
2219 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2220 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
2221 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
2222 "Expected no difference for dwProcessorType, got %d and %d\n",
2223 si
.dwProcessorType
, nsi
.dwProcessorType
);
2227 static void test_RegistryQuota(void)
2230 DWORD max_quota
, used_quota
;
2232 if (!pGetSystemRegistryQuota
)
2234 win_skip("GetSystemRegistryQuota is not available\n");
2238 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
2240 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2242 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
2244 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2246 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
2248 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2250 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
2252 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2255 static void test_TerminateProcess(void)
2257 static char cmdline
[] = "winver.exe";
2258 PROCESS_INFORMATION pi
;
2261 HANDLE dummy
, thread
;
2263 memset(&si
, 0, sizeof(si
));
2265 SetLastError(0xdeadbeef);
2266 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2267 ok(ret
, "CreateProcess error %u\n", GetLastError());
2269 SetLastError(0xdeadbeef);
2270 thread
= CreateRemoteThread(pi
.hProcess
, NULL
, 0, (void *)0xdeadbeef, NULL
, CREATE_SUSPENDED
, &ret
);
2271 ok(thread
!= 0, "CreateRemoteThread error %d\n", GetLastError());
2273 /* create a not closed thread handle duplicate in the target process */
2274 SetLastError(0xdeadbeef);
2275 ret
= DuplicateHandle(GetCurrentProcess(), thread
, pi
.hProcess
, &dummy
,
2276 0, FALSE
, DUPLICATE_SAME_ACCESS
);
2277 ok(ret
, "DuplicateHandle error %u\n", GetLastError());
2279 SetLastError(0xdeadbeef);
2280 ret
= TerminateThread(thread
, 0);
2281 ok(ret
, "TerminateThread error %u\n", GetLastError());
2282 CloseHandle(thread
);
2284 SetLastError(0xdeadbeef);
2285 ret
= TerminateProcess(pi
.hProcess
, 0);
2286 ok(ret
, "TerminateProcess error %u\n", GetLastError());
2288 CloseHandle(pi
.hProcess
);
2289 CloseHandle(pi
.hThread
);
2292 static void test_DuplicateHandle(void)
2294 char path
[MAX_PATH
], file_name
[MAX_PATH
];
2295 HANDLE f
, fmin
, out
;
2299 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2300 GetCurrentProcess(), &out
, 0, FALSE
,
2301 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2302 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2303 r
= GetHandleInformation(out
, &info
);
2304 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2305 ok(info
== 0, "info = %x\n", info
);
2306 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2309 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2310 GetCurrentProcess(), &out
, 0, TRUE
,
2311 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2312 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2313 r
= GetHandleInformation(out
, &info
);
2314 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2315 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2316 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2319 GetTempPathA(MAX_PATH
, path
);
2320 GetTempFileNameA(path
, "wt", 0, file_name
);
2321 f
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
2322 if (f
== INVALID_HANDLE_VALUE
)
2324 ok(0, "could not create %s\n", file_name
);
2328 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2329 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2330 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2331 ok(f
== out
, "f != out\n");
2332 r
= GetHandleInformation(out
, &info
);
2333 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2334 ok(info
== 0, "info = %x\n", info
);
2336 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2337 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2338 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2339 ok(f
== out
, "f != out\n");
2340 r
= GetHandleInformation(out
, &info
);
2341 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2342 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2344 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, HANDLE_FLAG_PROTECT_FROM_CLOSE
);
2345 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2346 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2347 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2348 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2349 ok(f
!= out
, "f == out\n");
2350 r
= GetHandleInformation(out
, &info
);
2351 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2352 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2353 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, 0);
2354 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2356 /* Test if DuplicateHandle allocates first free handle */
2367 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2368 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2369 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2370 ok(f
== out
, "f != out\n");
2372 DeleteFileA(file_name
);
2374 f
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2377 skip("DuplicateHandle on console handle\n");
2382 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2383 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2384 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2385 todo_wine
ok(f
!= out
, "f == out\n");
2389 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2390 static void _test_completion(int line
, HANDLE port
, DWORD ekey
, ULONG_PTR evalue
, ULONG_PTR eoverlapped
, DWORD wait
)
2392 LPOVERLAPPED overlapped
;
2397 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, wait
);
2399 ok_(__FILE__
, line
)(ret
, "GetQueuedCompletionStatus: %x\n", GetLastError());
2402 ok_(__FILE__
, line
)(key
== ekey
, "unexpected key %x\n", key
);
2403 ok_(__FILE__
, line
)(value
== evalue
, "unexpected value %p\n", (void *)value
);
2404 ok_(__FILE__
, line
)(overlapped
== (LPOVERLAPPED
)eoverlapped
, "unexpected overlapped %p\n", overlapped
);
2408 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2409 static void _create_process(int line
, const char *command
, LPPROCESS_INFORMATION pi
)
2412 char buffer
[MAX_PATH
];
2413 STARTUPINFOA si
= {0};
2415 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, command
);
2417 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, pi
);
2418 ok_(__FILE__
, line
)(ret
, "CreateProcess error %u\n", GetLastError());
2421 #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
2422 static void _test_assigned_proc(int line
, HANDLE job
, int expected_count
, ...)
2424 char buf
[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST
) + sizeof(ULONG_PTR
) * 20];
2425 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2431 memset(buf
, 0, sizeof(buf
));
2432 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2433 ok_(__FILE__
, line
)(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2436 todo_wine_if(expected_count
)
2437 ok_(__FILE__
, line
)(expected_count
== pid_list
->NumberOfAssignedProcesses
,
2438 "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n",
2439 expected_count
, pid_list
->NumberOfAssignedProcesses
);
2440 todo_wine_if(expected_count
)
2441 ok_(__FILE__
, line
)(expected_count
== pid_list
->NumberOfProcessIdsInList
,
2442 "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n",
2443 expected_count
, pid_list
->NumberOfProcessIdsInList
);
2445 va_start(valist
, expected_count
);
2446 for (n
= 0; n
< min(expected_count
, pid_list
->NumberOfProcessIdsInList
); ++n
)
2448 pid
= va_arg(valist
, DWORD
);
2449 ok_(__FILE__
, line
)(pid
== pid_list
->ProcessIdList
[n
],
2450 "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n",
2451 n
, pid
, pid_list
->ProcessIdList
[n
]);
2457 #define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc)
2458 static void _test_accounting(int line
, HANDLE job
, int total_proc
, int active_proc
, int terminated_proc
)
2460 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting
;
2464 memset(&basic_accounting
, 0, sizeof(basic_accounting
));
2465 ret
= pQueryInformationJobObject(job
, JobObjectBasicAccountingInformation
, &basic_accounting
, sizeof(basic_accounting
), &ret_len
);
2466 ok_(__FILE__
, line
)(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2469 /* Not going to check process times or page faults */
2471 todo_wine_if(total_proc
)
2472 ok_(__FILE__
, line
)(total_proc
== basic_accounting
.TotalProcesses
,
2473 "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n",
2474 total_proc
, basic_accounting
.TotalProcesses
);
2475 todo_wine_if(active_proc
)
2476 ok_(__FILE__
, line
)(active_proc
== basic_accounting
.ActiveProcesses
,
2477 "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n",
2478 active_proc
, basic_accounting
.ActiveProcesses
);
2479 ok_(__FILE__
, line
)(terminated_proc
== basic_accounting
.TotalTerminatedProcesses
,
2480 "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n",
2481 terminated_proc
, basic_accounting
.TotalTerminatedProcesses
);
2485 static void test_IsProcessInJob(void)
2488 PROCESS_INFORMATION pi
;
2492 if (!pIsProcessInJob
)
2494 win_skip("IsProcessInJob not available.\n");
2498 job
= pCreateJobObjectW(NULL
, NULL
);
2499 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2501 job2
= pCreateJobObjectW(NULL
, NULL
);
2502 ok(job2
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2504 create_process("wait", &pi
);
2507 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2508 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2509 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2510 test_assigned_proc(job
, 0);
2511 test_accounting(job
, 0, 0, 0);
2514 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2515 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2516 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2517 test_assigned_proc(job2
, 0);
2518 test_accounting(job2
, 0, 0, 0);
2521 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2522 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2523 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2525 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2526 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2529 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2530 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2531 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2532 test_assigned_proc(job
, 1, pi
.dwProcessId
);
2533 test_accounting(job
, 1, 1, 0);
2536 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2537 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2538 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2539 test_assigned_proc(job2
, 0);
2540 test_accounting(job2
, 0, 0, 0);
2543 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2544 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2545 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2547 TerminateProcess(pi
.hProcess
, 0);
2549 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2550 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2553 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2554 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2555 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2556 test_assigned_proc(job
, 0);
2557 test_accounting(job
, 1, 0, 0);
2559 CloseHandle(pi
.hProcess
);
2560 CloseHandle(pi
.hThread
);
2565 static void test_TerminateJobObject(void)
2568 PROCESS_INFORMATION pi
;
2572 job
= pCreateJobObjectW(NULL
, NULL
);
2573 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2574 test_assigned_proc(job
, 0);
2575 test_accounting(job
, 0, 0, 0);
2577 create_process("wait", &pi
);
2579 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2580 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2581 test_assigned_proc(job
, 1, pi
.dwProcessId
);
2582 test_accounting(job
, 1, 1, 0);
2584 ret
= pTerminateJobObject(job
, 123);
2585 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2587 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2588 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2589 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2590 test_assigned_proc(job
, 0);
2591 test_accounting(job
, 1, 0, 0);
2593 ret
= GetExitCodeProcess(pi
.hProcess
, &dwret
);
2594 ok(ret
, "GetExitCodeProcess error %u\n", GetLastError());
2595 ok(dwret
== 123 || broken(dwret
== 0) || broken(dwret
== 259) /* randomly fails on Win 2000 / XP */,
2596 "wrong exitcode %u\n", dwret
);
2598 CloseHandle(pi
.hProcess
);
2599 CloseHandle(pi
.hThread
);
2601 /* Test adding an already terminated process to a job object */
2602 create_process("exit", &pi
);
2604 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2605 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2607 SetLastError(0xdeadbeef);
2608 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2609 ok(!ret
, "AssignProcessToJobObject unexpectedly succeeded\n");
2610 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2611 test_assigned_proc(job
, 0);
2612 test_accounting(job
, 1, 0, 0);
2614 CloseHandle(pi
.hProcess
);
2615 CloseHandle(pi
.hThread
);
2620 static void test_QueryInformationJobObject(void)
2622 char buf
[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST
) + sizeof(ULONG_PTR
) * 4];
2623 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2624 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info
;
2625 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit_info
= &ext_limit_info
.BasicLimitInformation
;
2626 DWORD dwret
, ret_len
;
2627 PROCESS_INFORMATION pi
[2];
2631 job
= pCreateJobObjectW(NULL
, NULL
);
2632 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2634 /* Only active processes are returned */
2635 create_process("exit", &pi
[0]);
2636 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2637 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2638 dwret
= WaitForSingleObject(pi
[0].hProcess
, 1000);
2639 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2641 CloseHandle(pi
[0].hProcess
);
2642 CloseHandle(pi
[0].hThread
);
2644 create_process("wait", &pi
[0]);
2645 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2646 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2648 create_process("wait", &pi
[1]);
2649 ret
= pAssignProcessToJobObject(job
, pi
[1].hProcess
);
2650 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2652 SetLastError(0xdeadbeef);
2653 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2654 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
), &ret_len
);
2655 ok(!ret
, "QueryInformationJobObject expected failure\n");
2656 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2658 SetLastError(0xdeadbeef);
2659 memset(buf
, 0, sizeof(buf
));
2660 pid_list
->NumberOfAssignedProcesses
= 42;
2661 pid_list
->NumberOfProcessIdsInList
= 42;
2662 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2663 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[1]), &ret_len
);
2665 ok(!ret
, "QueryInformationJobObject expected failure\n");
2667 expect_eq_d(ERROR_MORE_DATA
, GetLastError());
2671 expect_eq_d(42, pid_list
->NumberOfAssignedProcesses
);
2673 expect_eq_d(42, pid_list
->NumberOfProcessIdsInList
);
2676 memset(buf
, 0, sizeof(buf
));
2677 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2678 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2681 if (pid_list
->NumberOfAssignedProcesses
== 3) /* Win 8 */
2682 win_skip("Number of assigned processes broken on Win 8\n");
2685 ULONG_PTR
*list
= pid_list
->ProcessIdList
;
2688 ok(ret_len
== FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[2]),
2689 "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2692 expect_eq_d(2, pid_list
->NumberOfAssignedProcesses
);
2694 expect_eq_d(2, pid_list
->NumberOfProcessIdsInList
);
2696 expect_eq_d(pi
[0].dwProcessId
, list
[0]);
2698 expect_eq_d(pi
[1].dwProcessId
, list
[1]);
2702 /* test JobObjectBasicLimitInformation */
2703 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2704 sizeof(*basic_limit_info
) - 1, &ret_len
);
2705 ok(!ret
, "QueryInformationJobObject expected failure\n");
2706 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2708 ret_len
= 0xdeadbeef;
2709 memset(basic_limit_info
, 0x11, sizeof(*basic_limit_info
));
2710 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2711 sizeof(*basic_limit_info
), &ret_len
);
2712 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2713 ok(ret_len
== sizeof(*basic_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2714 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2716 /* test JobObjectExtendedLimitInformation */
2717 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2718 sizeof(ext_limit_info
) - 1, &ret_len
);
2719 ok(!ret
, "QueryInformationJobObject expected failure\n");
2720 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2722 ret_len
= 0xdeadbeef;
2723 memset(&ext_limit_info
, 0x11, sizeof(ext_limit_info
));
2724 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2725 sizeof(ext_limit_info
), &ret_len
);
2726 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2727 ok(ret_len
== sizeof(ext_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2728 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2730 TerminateProcess(pi
[0].hProcess
, 0);
2731 CloseHandle(pi
[0].hProcess
);
2732 CloseHandle(pi
[0].hThread
);
2734 TerminateProcess(pi
[1].hProcess
, 0);
2735 CloseHandle(pi
[1].hProcess
);
2736 CloseHandle(pi
[1].hThread
);
2741 static void test_CompletionPort(void)
2743 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
2744 PROCESS_INFORMATION pi
;
2749 job
= pCreateJobObjectW(NULL
, NULL
);
2750 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2752 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
2753 ok(port
!= NULL
, "CreateIoCompletionPort error %u\n", GetLastError());
2755 port_info
.CompletionKey
= job
;
2756 port_info
.CompletionPort
= port
;
2757 ret
= pSetInformationJobObject(job
, JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
2758 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2760 create_process("wait", &pi
);
2762 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2763 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2765 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2767 TerminateProcess(pi
.hProcess
, 0);
2768 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2769 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2771 test_completion(port
, JOB_OBJECT_MSG_EXIT_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2772 test_completion(port
, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
, (DWORD_PTR
)job
, 0, 100);
2774 CloseHandle(pi
.hProcess
);
2775 CloseHandle(pi
.hThread
);
2780 static void test_KillOnJobClose(void)
2782 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2783 PROCESS_INFORMATION pi
;
2788 job
= pCreateJobObjectW(NULL
, NULL
);
2789 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2791 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
;
2792 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2793 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
2795 win_skip("Kill on job close limit not available\n");
2798 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2799 test_assigned_proc(job
, 0);
2800 test_accounting(job
, 0, 0, 0);
2802 create_process("wait", &pi
);
2804 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2805 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2806 test_assigned_proc(job
, 1, pi
.dwProcessId
);
2807 test_accounting(job
, 1, 1, 0);
2811 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2812 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2813 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2815 CloseHandle(pi
.hProcess
);
2816 CloseHandle(pi
.hThread
);
2819 static void test_WaitForJobObject(void)
2822 PROCESS_INFORMATION pi
;
2826 /* test waiting for a job object when the process is killed */
2827 job
= pCreateJobObjectW(NULL
, NULL
);
2828 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2830 dwret
= WaitForSingleObject(job
, 100);
2831 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2833 create_process("wait", &pi
);
2835 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2836 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2838 dwret
= WaitForSingleObject(job
, 100);
2839 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2841 ret
= pTerminateJobObject(job
, 123);
2842 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2844 dwret
= WaitForSingleObject(job
, 500);
2845 ok(dwret
== WAIT_OBJECT_0
|| broken(dwret
== WAIT_TIMEOUT
),
2846 "WaitForSingleObject returned %u\n", dwret
);
2848 if (dwret
== WAIT_TIMEOUT
) /* Win 2000/XP */
2853 ok(0, "HACK: Killing process to speed up the test\n");
2854 TerminateProcess(pi
.hProcess
, 0);
2857 CloseHandle(pi
.hProcess
);
2858 CloseHandle(pi
.hThread
);
2860 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2864 /* the object is not reset immediately */
2865 dwret
= WaitForSingleObject(job
, 100);
2866 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2868 CloseHandle(pi
.hProcess
);
2869 CloseHandle(pi
.hThread
);
2871 /* creating a new process doesn't reset the signalled state */
2872 create_process("wait", &pi
);
2874 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2875 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2877 dwret
= WaitForSingleObject(job
, 100);
2878 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2880 ret
= pTerminateJobObject(job
, 123);
2881 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2883 CloseHandle(pi
.hProcess
);
2884 CloseHandle(pi
.hThread
);
2888 /* repeat the test, but this time the process terminates properly */
2889 job
= pCreateJobObjectW(NULL
, NULL
);
2890 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2892 dwret
= WaitForSingleObject(job
, 100);
2893 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2895 create_process("exit", &pi
);
2897 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2898 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2900 dwret
= WaitForSingleObject(job
, 100);
2901 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2903 CloseHandle(pi
.hProcess
);
2904 CloseHandle(pi
.hThread
);
2908 static HANDLE
test_AddSelfToJob(void)
2913 job
= pCreateJobObjectW(NULL
, NULL
);
2914 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2916 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
2917 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2918 test_assigned_proc(job
, 1, GetCurrentProcessId());
2919 test_accounting(job
, 1, 1, 0);
2924 static void test_jobInheritance(HANDLE job
)
2926 char buffer
[MAX_PATH
];
2927 PROCESS_INFORMATION pi
;
2928 STARTUPINFOA si
= {0};
2932 if (!pIsProcessInJob
)
2934 win_skip("IsProcessInJob not available.\n");
2938 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2940 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2941 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2944 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2945 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2946 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2947 test_assigned_proc(job
, 2, GetCurrentProcessId(), pi
.dwProcessId
);
2948 test_accounting(job
, 2, 2, 0);
2950 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2951 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2953 CloseHandle(pi
.hProcess
);
2954 CloseHandle(pi
.hThread
);
2957 static void test_BreakawayOk(HANDLE job
)
2959 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2960 PROCESS_INFORMATION pi
;
2961 STARTUPINFOA si
= {0};
2962 char buffer
[MAX_PATH
];
2966 if (!pIsProcessInJob
)
2968 win_skip("IsProcessInJob not available.\n");
2972 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2974 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2975 ok(!ret
, "CreateProcessA expected failure\n");
2976 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2977 test_assigned_proc(job
, 1, GetCurrentProcessId());
2978 test_accounting(job
, 2, 1, 0);
2982 TerminateProcess(pi
.hProcess
, 0);
2984 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2985 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2987 CloseHandle(pi
.hProcess
);
2988 CloseHandle(pi
.hThread
);
2991 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
2992 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2993 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2995 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2996 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2998 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2999 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
3000 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
3001 test_assigned_proc(job
, 1, GetCurrentProcessId());
3002 test_accounting(job
, 2, 1, 0);
3004 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
3005 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
3007 CloseHandle(pi
.hProcess
);
3008 CloseHandle(pi
.hThread
);
3010 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
3011 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
3012 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
3014 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
3015 ok(ret
, "CreateProcess error %u\n", GetLastError());
3017 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
3018 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
3019 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
3020 test_assigned_proc(job
, 1, GetCurrentProcessId());
3021 test_accounting(job
, 2, 1, 0);
3023 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
3024 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
3026 CloseHandle(pi
.hProcess
);
3027 CloseHandle(pi
.hThread
);
3029 /* unset breakaway ok */
3030 limit_info
.BasicLimitInformation
.LimitFlags
= 0;
3031 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
3032 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
3035 static void test_StartupNoConsole(void)
3038 char buffer
[MAX_PATH
];
3039 STARTUPINFOA startup
;
3040 PROCESS_INFORMATION info
;
3042 memset(&startup
, 0, sizeof(startup
));
3043 startup
.cb
= sizeof(startup
);
3044 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3045 startup
.wShowWindow
= SW_SHOWNORMAL
;
3046 get_file_name(resfile
);
3047 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
3048 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
3049 &info
), "CreateProcess\n");
3050 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
3051 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
3052 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
3053 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
3054 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
3055 okChildInt("TEB", "hStdInput", 0);
3056 okChildInt("TEB", "hStdOutput", 0);
3057 okChildInt("TEB", "hStdError", 0);
3059 DeleteFileA(resfile
);
3063 static void test_DetachConsoleHandles(void)
3066 char buffer
[MAX_PATH
];
3067 STARTUPINFOA startup
;
3068 PROCESS_INFORMATION info
;
3071 memset(&startup
, 0, sizeof(startup
));
3072 startup
.cb
= sizeof(startup
);
3073 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
3074 startup
.wShowWindow
= SW_SHOWNORMAL
;
3075 startup
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
3076 startup
.hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
3077 startup
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
3078 get_file_name(resfile
);
3079 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
3080 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
3081 &info
), "CreateProcess\n");
3082 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
3083 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
3085 result
= GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile
);
3086 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3087 result
= GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile
);
3088 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3089 result
= GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile
);
3090 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3091 result
= GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile
);
3092 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3093 result
= GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile
);
3094 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3095 result
= GetPrivateProfileIntA("TEB", "hStdError", 0, resfile
);
3096 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3099 DeleteFileA(resfile
);
3103 #if defined(__i386__) || defined(__x86_64__)
3104 static BOOL
read_nt_header(HANDLE process_handle
, MEMORY_BASIC_INFORMATION
*mbi
,
3105 IMAGE_NT_HEADERS
*nt_header
)
3107 IMAGE_DOS_HEADER dos_header
;
3109 if (!ReadProcessMemory(process_handle
, mbi
->BaseAddress
, &dos_header
, sizeof(dos_header
), NULL
))
3112 if ((dos_header
.e_magic
!= IMAGE_DOS_SIGNATURE
) ||
3113 ((ULONG
)dos_header
.e_lfanew
> mbi
->RegionSize
) ||
3114 (dos_header
.e_lfanew
< sizeof(dos_header
)))
3117 if (!ReadProcessMemory(process_handle
, (char *)mbi
->BaseAddress
+ dos_header
.e_lfanew
,
3118 nt_header
, sizeof(*nt_header
), NULL
))
3121 return (nt_header
->Signature
== IMAGE_NT_SIGNATURE
);
3124 static PVOID
get_process_exe(HANDLE process_handle
, IMAGE_NT_HEADERS
*nt_header
)
3126 PVOID exe_base
, address
;
3127 MEMORY_BASIC_INFORMATION mbi
;
3129 /* Find the EXE base in the new process */
3131 for (address
= NULL
;
3132 VirtualQueryEx(process_handle
, address
, &mbi
, sizeof(mbi
)) ;
3133 address
= (char *)mbi
.BaseAddress
+ mbi
.RegionSize
) {
3134 if ((mbi
.Type
== SEC_IMAGE
) &&
3135 read_nt_header(process_handle
, &mbi
, nt_header
) &&
3136 !(nt_header
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)) {
3137 exe_base
= mbi
.BaseAddress
;
3145 static BOOL
are_imports_resolved(HANDLE process_handle
, PVOID module_base
, IMAGE_NT_HEADERS
*nt_header
)
3148 IMAGE_IMPORT_DESCRIPTOR iid
;
3149 ULONG_PTR orig_iat_entry_value
, iat_entry_value
;
3151 ok(nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
, "Import table VA is zero\n");
3152 ok(nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].Size
, "Import table Size is zero\n");
3154 if (!nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
||
3155 !nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].Size
)
3158 /* Read the first IID */
3159 ret
= ReadProcessMemory(process_handle
,
3160 (char *)module_base
+ nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
,
3161 &iid
, sizeof(iid
), NULL
);
3162 ok(ret
, "Failed to read remote module IID (%d)\n", GetLastError());
3164 /* Validate the IID is present and not a bound import, and that we have
3165 an OriginalFirstThunk to compare with */
3166 ok(iid
.Name
, "Module first IID does not have a Name\n");
3167 ok(iid
.FirstThunk
, "Module first IID does not have a FirstThunk\n");
3168 ok(!iid
.TimeDateStamp
, "Module first IID is a bound import (UNSUPPORTED for current test)\n");
3169 ok(iid
.OriginalFirstThunk
, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3171 /* Read a single IAT entry from the FirstThunk */
3172 ret
= ReadProcessMemory(process_handle
, (char *)module_base
+ iid
.FirstThunk
,
3173 &iat_entry_value
, sizeof(iat_entry_value
), NULL
);
3174 ok(ret
, "Failed to read IAT entry from FirstThunk (%d)\n", GetLastError());
3175 ok(iat_entry_value
, "IAT entry in FirstThunk is NULL\n");
3177 /* Read a single IAT entry from the OriginalFirstThunk */
3178 ret
= ReadProcessMemory(process_handle
, (char *)module_base
+ iid
.OriginalFirstThunk
,
3179 &orig_iat_entry_value
, sizeof(orig_iat_entry_value
), NULL
);
3180 ok(ret
, "Failed to read IAT entry from OriginalFirstThunk (%d)\n", GetLastError());
3181 ok(orig_iat_entry_value
, "IAT entry in OriginalFirstThunk is NULL\n");
3183 return iat_entry_value
!= orig_iat_entry_value
;
3186 static void test_SuspendProcessNewThread(void)
3189 STARTUPINFOA si
= {0};
3190 PROCESS_INFORMATION pi
= {0};
3191 PVOID exe_base
, exit_thread_ptr
;
3192 IMAGE_NT_HEADERS nt_header
;
3193 HANDLE thread_handle
= NULL
;
3194 DWORD dret
, exit_code
= 0;
3197 exit_thread_ptr
= GetProcAddress(hkernel32
, "ExitThread");
3198 ok(exit_thread_ptr
!= NULL
, "GetProcAddress ExitThread failed\n");
3201 ret
= CreateProcessA(NULL
, selfname
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
3202 ok(ret
, "Failed to create process (%d)\n", GetLastError());
3204 exe_base
= get_process_exe(pi
.hProcess
, &nt_header
);
3205 ok(exe_base
!= NULL
, "Could not find EXE in remote process\n");
3207 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3208 ok(!ret
, "IAT entry resolved prematurely\n");
3210 thread_handle
= CreateRemoteThread(pi
.hProcess
, NULL
, 0,
3211 (LPTHREAD_START_ROUTINE
)exit_thread_ptr
,
3212 (PVOID
)(ULONG_PTR
)0x1234, CREATE_SUSPENDED
, NULL
);
3213 ok(thread_handle
!= NULL
, "Could not create remote thread (%d)\n", GetLastError());
3215 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3216 ok(!ret
, "IAT entry resolved prematurely\n");
3218 ctx
.ContextFlags
= CONTEXT_ALL
;
3219 ret
= GetThreadContext( thread_handle
, &ctx
);
3220 ok( ret
, "Failed retrieving remote thread context (%d)\n", GetLastError() );
3221 ok( ctx
.ContextFlags
== CONTEXT_ALL
, "wrong flags %x\n", ctx
.ContextFlags
);
3223 ok( !ctx
.Rax
, "rax is not zero %lx\n", ctx
.Rax
);
3224 ok( !ctx
.Rbx
, "rbx is not zero %lx\n", ctx
.Rbx
);
3225 ok( ctx
.Rcx
== (ULONG_PTR
)exit_thread_ptr
, "wrong rcx %lx/%p\n", ctx
.Rcx
, exit_thread_ptr
);
3226 ok( ctx
.Rdx
== 0x1234, "wrong rdx %lx\n", ctx
.Rdx
);
3227 ok( !ctx
.Rsi
, "rsi is not zero %lx\n", ctx
.Rsi
);
3228 ok( !ctx
.Rdi
, "rdi is not zero %lx\n", ctx
.Rdi
);
3229 ok( !ctx
.Rbp
, "rbp is not zero %lx\n", ctx
.Rbp
);
3230 ok( !ctx
.R8
, "r8 is not zero %lx\n", ctx
.R8
);
3231 ok( !ctx
.R9
, "r9 is not zero %lx\n", ctx
.R9
);
3232 ok( !ctx
.R10
, "r10 is not zero %lx\n", ctx
.R10
);
3233 ok( !ctx
.R11
, "r11 is not zero %lx\n", ctx
.R11
);
3234 ok( !ctx
.R12
, "r12 is not zero %lx\n", ctx
.R12
);
3235 ok( !ctx
.R13
, "r13 is not zero %lx\n", ctx
.R13
);
3236 ok( !ctx
.R14
, "r14 is not zero %lx\n", ctx
.R14
);
3237 ok( !ctx
.R15
, "r15 is not zero %lx\n", ctx
.R15
);
3238 ok( !((ctx
.Rsp
+ 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx
.Rsp
);
3239 ok( ctx
.EFlags
== 0x200, "wrong flags %08x\n", ctx
.EFlags
);
3240 ok( ctx
.MxCsr
== 0x1f80, "wrong mxcsr %08x\n", ctx
.MxCsr
);
3241 ok( ctx
.FltSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FltSave
.ControlWord
);
3243 ok( !ctx
.Ebp
|| broken(ctx
.Ebp
), /* winxp */ "ebp is not zero %08x\n", ctx
.Ebp
);
3244 if (!ctx
.Ebp
) /* winxp is completely different */
3246 ok( !ctx
.Ecx
, "ecx is not zero %08x\n", ctx
.Ecx
);
3247 ok( !ctx
.Edx
, "edx is not zero %08x\n", ctx
.Edx
);
3248 ok( !ctx
.Esi
, "esi is not zero %08x\n", ctx
.Esi
);
3249 ok( !ctx
.Edi
, "edi is not zero %08x\n", ctx
.Edi
);
3251 ok( ctx
.Eax
== (ULONG_PTR
)exit_thread_ptr
, "wrong eax %08x/%p\n", ctx
.Eax
, exit_thread_ptr
);
3252 ok( ctx
.Ebx
== 0x1234, "wrong ebx %08x\n", ctx
.Ebx
);
3253 ok( !((ctx
.Esp
+ 0x10) & 0xfff) || broken( !((ctx
.Esp
+ 4) & 0xfff) ), /* winxp, w2k3 */
3254 "esp is not at top of stack page or properly aligned: %08x\n", ctx
.Esp
);
3255 ok( (ctx
.EFlags
& ~2) == 0x200, "wrong flags %08x\n", ctx
.EFlags
);
3256 ok( (WORD
)ctx
.FloatSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FloatSave
.ControlWord
);
3257 ok( *(WORD
*)ctx
.ExtendedRegisters
== 0x27f, "wrong control %08x\n", *(WORD
*)ctx
.ExtendedRegisters
);
3260 ResumeThread( thread_handle
);
3261 dret
= WaitForSingleObject(thread_handle
, 60000);
3262 ok(dret
== WAIT_OBJECT_0
, "Waiting for remote thread failed (%d)\n", GetLastError());
3263 ret
= GetExitCodeThread(thread_handle
, &exit_code
);
3264 ok(ret
, "Failed to retrieve remote thread exit code (%d)\n", GetLastError());
3265 ok(exit_code
== 0x1234, "Invalid remote thread exit code\n");
3267 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3268 ok(ret
, "EXE IAT entry not resolved\n");
3271 CloseHandle(thread_handle
);
3273 TerminateProcess(pi
.hProcess
, 0);
3274 WaitForSingleObject(pi
.hProcess
, 10000);
3275 CloseHandle(pi
.hProcess
);
3276 CloseHandle(pi
.hThread
);
3279 static void test_SuspendProcessState(void)
3283 ULONG pipe_write_buf
;
3284 ULONG pipe_read_buf
;
3285 ULONG bytes_returned
;
3286 CHAR pipe_name
[MAX_PATH
];
3290 struct remote_rop_chain
3292 void *exit_process_ptr
;
3297 ULONG_PTR pipe_read_buf_size
;
3298 ULONG_PTR bytes_returned
;
3302 struct remote_rop_chain
3304 void *exit_process_ptr
;
3305 ULONG_PTR pipe_name
;
3306 ULONG_PTR pipe_write_buf
;
3307 ULONG_PTR pipe_write_buf_size
;
3308 ULONG_PTR pipe_read_buf
;
3309 ULONG_PTR pipe_read_buf_size
;
3310 ULONG_PTR bytes_returned
;
3312 void *unreached_ret
;
3313 ULONG_PTR exit_code
;
3317 static const char pipe_name
[] = "\\\\.\\pipe\\TestPipe";
3318 static const ULONG pipe_write_magic
= 0x454e4957;
3319 STARTUPINFOA si
= {0};
3320 PROCESS_INFORMATION pi
= {0};
3321 PVOID exe_base
, remote_pipe_params
, exit_process_ptr
,
3323 IMAGE_NT_HEADERS nt_header
;
3324 struct pipe_params pipe_params
;
3325 struct remote_rop_chain rop_chain
;
3327 HANDLE server_pipe_handle
;
3328 BOOL pipe_connected
;
3329 ULONG pipe_magic
, numb
;
3331 void *entry_ptr
, *peb_ptr
;
3334 exit_process_ptr
= GetProcAddress(hkernel32
, "ExitProcess");
3335 ok(exit_process_ptr
!= NULL
, "GetProcAddress ExitProcess failed\n");
3337 call_named_pipe_a
= GetProcAddress(hkernel32
, "CallNamedPipeA");
3338 ok(call_named_pipe_a
!= NULL
, "GetProcAddress CallNamedPipeA failed\n");
3341 ret
= CreateProcessA(NULL
, selfname
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
3342 ok(ret
, "Failed to create process (%d)\n", GetLastError());
3344 exe_base
= get_process_exe(pi
.hProcess
, &nt_header
);
3345 /* Make sure we found the EXE in the new process */
3346 ok(exe_base
!= NULL
, "Could not find EXE in remote process\n");
3348 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3349 ok(!ret
, "IAT entry resolved prematurely\n");
3351 server_pipe_handle
= CreateNamedPipeA(pipe_name
, PIPE_ACCESS_DUPLEX
| FILE_FLAG_WRITE_THROUGH
,
3352 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
, 1, 0x20000, 0x20000,
3354 ok(server_pipe_handle
!= INVALID_HANDLE_VALUE
, "Failed to create communication pipe (%d)\n", GetLastError());
3356 /* Set up the remote process environment */
3357 ctx
.ContextFlags
= CONTEXT_ALL
;
3358 ret
= GetThreadContext(pi
.hThread
, &ctx
);
3359 ok(ret
, "Failed retrieving remote thread context (%d)\n", GetLastError());
3360 ok( ctx
.ContextFlags
== CONTEXT_ALL
, "wrong flags %x\n", ctx
.ContextFlags
);
3362 remote_pipe_params
= VirtualAllocEx(pi
.hProcess
, NULL
, sizeof(pipe_params
), MEM_COMMIT
, PAGE_READWRITE
);
3363 ok(remote_pipe_params
!= NULL
, "Failed allocating memory in remote process (%d)\n", GetLastError());
3365 pipe_params
.pipe_write_buf
= pipe_write_magic
;
3366 pipe_params
.pipe_read_buf
= 0;
3367 pipe_params
.bytes_returned
= 0;
3368 strcpy(pipe_params
.pipe_name
, pipe_name
);
3370 ret
= WriteProcessMemory(pi
.hProcess
, remote_pipe_params
,
3371 &pipe_params
, sizeof(pipe_params
), NULL
);
3372 ok(ret
, "Failed to write to remote process memory (%d)\n", GetLastError());
3375 ok( !ctx
.Rax
, "rax is not zero %lx\n", ctx
.Rax
);
3376 ok( !ctx
.Rbx
, "rbx is not zero %lx\n", ctx
.Rbx
);
3377 ok( !ctx
.Rsi
, "rsi is not zero %lx\n", ctx
.Rsi
);
3378 ok( !ctx
.Rdi
, "rdi is not zero %lx\n", ctx
.Rdi
);
3379 ok( !ctx
.Rbp
, "rbp is not zero %lx\n", ctx
.Rbp
);
3380 ok( !ctx
.R8
, "r8 is not zero %lx\n", ctx
.R8
);
3381 ok( !ctx
.R9
, "r9 is not zero %lx\n", ctx
.R9
);
3382 ok( !ctx
.R10
, "r10 is not zero %lx\n", ctx
.R10
);
3383 ok( !ctx
.R11
, "r11 is not zero %lx\n", ctx
.R11
);
3384 ok( !ctx
.R12
, "r12 is not zero %lx\n", ctx
.R12
);
3385 ok( !ctx
.R13
, "r13 is not zero %lx\n", ctx
.R13
);
3386 ok( !ctx
.R14
, "r14 is not zero %lx\n", ctx
.R14
);
3387 ok( !ctx
.R15
, "r15 is not zero %lx\n", ctx
.R15
);
3388 ok( !((ctx
.Rsp
+ 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx
.Rsp
);
3389 ok( ctx
.EFlags
== 0x200, "wrong flags %08x\n", ctx
.EFlags
);
3390 ok( ctx
.MxCsr
== 0x1f80, "wrong mxcsr %08x\n", ctx
.MxCsr
);
3391 ok( ctx
.FltSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FltSave
.ControlWord
);
3392 entry_ptr
= (void *)ctx
.Rcx
;
3393 peb_ptr
= (void *)ctx
.Rdx
;
3395 rop_chain
.exit_process_ptr
= exit_process_ptr
;
3396 ctx
.Rcx
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_name
);
3397 ctx
.Rdx
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_write_buf
);
3398 ctx
.R8
= sizeof(pipe_params
.pipe_write_buf
);
3399 ctx
.R9
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_read_buf
);
3400 rop_chain
.pipe_read_buf_size
= sizeof(pipe_params
.pipe_read_buf
);
3401 rop_chain
.bytes_returned
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, bytes_returned
);
3402 rop_chain
.timeout
= 10000;
3404 ctx
.Rip
= (ULONG_PTR
)call_named_pipe_a
;
3405 ctx
.Rsp
-= sizeof(rop_chain
);
3406 ret
= WriteProcessMemory(pi
.hProcess
, (void *)ctx
.Rsp
, &rop_chain
, sizeof(rop_chain
), NULL
);
3407 ok(ret
, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3409 ok( !ctx
.Ebp
|| broken(ctx
.Ebp
), /* winxp */ "ebp is not zero %08x\n", ctx
.Ebp
);
3410 if (!ctx
.Ebp
) /* winxp is completely different */
3412 ok( !ctx
.Ecx
, "ecx is not zero %08x\n", ctx
.Ecx
);
3413 ok( !ctx
.Edx
, "edx is not zero %08x\n", ctx
.Edx
);
3414 ok( !ctx
.Esi
, "esi is not zero %08x\n", ctx
.Esi
);
3415 ok( !ctx
.Edi
, "edi is not zero %08x\n", ctx
.Edi
);
3417 ok( !((ctx
.Esp
+ 0x10) & 0xfff) || broken( !((ctx
.Esp
+ 4) & 0xfff) ), /* winxp, w2k3 */
3418 "esp is not at top of stack page or properly aligned: %08x\n", ctx
.Esp
);
3419 ok( (ctx
.EFlags
& ~2) == 0x200, "wrong flags %08x\n", ctx
.EFlags
);
3420 ok( (WORD
)ctx
.FloatSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FloatSave
.ControlWord
);
3421 ok( *(WORD
*)ctx
.ExtendedRegisters
== 0x27f, "wrong control %08x\n", *(WORD
*)ctx
.ExtendedRegisters
);
3422 entry_ptr
= (void *)ctx
.Eax
;
3423 peb_ptr
= (void *)ctx
.Ebx
;
3425 rop_chain
.exit_process_ptr
= exit_process_ptr
;
3426 rop_chain
.pipe_name
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_name
);
3427 rop_chain
.pipe_write_buf
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_write_buf
);
3428 rop_chain
.pipe_write_buf_size
= sizeof(pipe_params
.pipe_write_buf
);
3429 rop_chain
.pipe_read_buf
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_read_buf
);
3430 rop_chain
.pipe_read_buf_size
= sizeof(pipe_params
.pipe_read_buf
);
3431 rop_chain
.bytes_returned
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, bytes_returned
);
3432 rop_chain
.timeout
= 10000;
3433 rop_chain
.exit_code
= 0;
3435 ctx
.Eip
= (ULONG_PTR
)call_named_pipe_a
;
3436 ctx
.Esp
-= sizeof(rop_chain
);
3437 ret
= WriteProcessMemory(pi
.hProcess
, (void *)ctx
.Esp
, &rop_chain
, sizeof(rop_chain
), NULL
);
3438 ok(ret
, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3441 ret
= ReadProcessMemory( pi
.hProcess
, peb_ptr
, &child_peb
, sizeof(child_peb
), NULL
);
3442 ok( ret
, "Failed to read PEB (%u)\n", GetLastError() );
3443 ok( child_peb
.ImageBaseAddress
== exe_base
, "wrong base %p/%p\n",
3444 child_peb
.ImageBaseAddress
, exe_base
);
3445 ok( entry_ptr
== (char *)exe_base
+ nt_header
.OptionalHeader
.AddressOfEntryPoint
,
3446 "wrong entry point %p/%p\n", entry_ptr
,
3447 (char *)exe_base
+ nt_header
.OptionalHeader
.AddressOfEntryPoint
);
3449 ret
= SetThreadContext(pi
.hThread
, &ctx
);
3450 ok(ret
, "Failed to set remote thread context (%d)\n", GetLastError());
3452 ResumeThread(pi
.hThread
);
3454 pipe_connected
= ConnectNamedPipe(server_pipe_handle
, NULL
) || (GetLastError() == ERROR_PIPE_CONNECTED
);
3455 ok(pipe_connected
, "Pipe did not connect\n");
3457 ret
= ReadFile(server_pipe_handle
, &pipe_magic
, sizeof(pipe_magic
), &numb
, NULL
);
3458 ok(ret
, "Failed to read buffer from pipe (%d)\n", GetLastError());
3460 ok(pipe_magic
== pipe_write_magic
, "Did not get the correct magic from the remote process\n");
3462 /* Validate the Imports, at this point the thread in the new process should have
3463 initialized the EXE module imports and call each dll DllMain notifying it on
3464 the new thread in the process. */
3465 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3466 ok(ret
, "EXE IAT is not resolved\n");
3468 ret
= WriteFile(server_pipe_handle
, &pipe_magic
, sizeof(pipe_magic
), &numb
, NULL
);
3469 ok(ret
, "Failed to write the magic back to the pipe (%d)\n", GetLastError());
3471 CloseHandle(server_pipe_handle
);
3472 TerminateProcess(pi
.hProcess
, 0);
3473 WaitForSingleObject(pi
.hProcess
, 10000);
3474 CloseHandle(pi
.hProcess
);
3475 CloseHandle(pi
.hThread
);
3478 static void test_SuspendProcessNewThread(void)
3481 static void test_SuspendProcessState(void)
3486 static void test_DetachStdHandles(void)
3489 char buffer
[MAX_PATH
], tempfile
[MAX_PATH
];
3490 STARTUPINFOA startup
;
3491 PROCESS_INFORMATION info
;
3492 HANDLE hstdin
, hstdout
, hstderr
, htemp
;
3495 hstdin
= GetStdHandle(STD_INPUT_HANDLE
);
3496 hstdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
3497 hstderr
= GetStdHandle(STD_ERROR_HANDLE
);
3499 get_file_name(tempfile
);
3500 htemp
= CreateFileA(tempfile
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
3501 ok(htemp
!= INVALID_HANDLE_VALUE
, "failed opening temporary file\n");
3503 memset(&startup
, 0, sizeof(startup
));
3504 startup
.cb
= sizeof(startup
);
3505 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3506 startup
.wShowWindow
= SW_SHOWNORMAL
;
3507 get_file_name(resfile
);
3508 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
3510 SetStdHandle(STD_INPUT_HANDLE
, htemp
);
3511 SetStdHandle(STD_OUTPUT_HANDLE
, htemp
);
3512 SetStdHandle(STD_ERROR_HANDLE
, htemp
);
3514 res
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
3517 SetStdHandle(STD_INPUT_HANDLE
, hstdin
);
3518 SetStdHandle(STD_OUTPUT_HANDLE
, hstdout
);
3519 SetStdHandle(STD_ERROR_HANDLE
, hstderr
);
3521 ok(res
, "CreateProcess failed\n");
3522 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
3523 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
3524 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
3525 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
3526 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
3527 okChildInt("TEB", "hStdInput", 0);
3528 okChildInt("TEB", "hStdOutput", 0);
3529 okChildInt("TEB", "hStdError", 0);
3531 DeleteFileA(resfile
);
3534 DeleteFileA(tempfile
);
3538 static void test_GetNumaProcessorNode(void)
3545 if (!pGetNumaProcessorNode
)
3547 win_skip("GetNumaProcessorNode is missing\n");
3552 for (i
= 0; i
< 256; i
++)
3554 SetLastError(0xdeadbeef);
3555 node
= (i
< si
.dwNumberOfProcessors
) ? 0xFF : 0xAA;
3556 ret
= pGetNumaProcessorNode(i
, &node
);
3557 if (i
< si
.dwNumberOfProcessors
)
3559 ok(ret
, "GetNumaProcessorNode returned FALSE for processor %d\n", i
);
3560 ok(node
!= 0xFF, "expected node != 0xFF, but got 0xFF\n");
3564 ok(!ret
, "GetNumaProcessorNode returned TRUE for processor %d\n", i
);
3565 ok(node
== 0xFF || broken(node
== 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node
);
3566 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3571 static void test_session_info(void)
3573 DWORD session_id
, active_session
;
3576 if (!pProcessIdToSessionId
)
3578 win_skip("ProcessIdToSessionId is missing\n");
3582 r
= pProcessIdToSessionId(GetCurrentProcessId(), &session_id
);
3583 ok(r
, "ProcessIdToSessionId failed: %u\n", GetLastError());
3584 trace("session_id = %x\n", session_id
);
3586 active_session
= pWTSGetActiveConsoleSessionId();
3587 trace("active_session = %x\n", active_session
);
3590 static void test_process_info(void)
3593 static const ULONG info_size
[] =
3595 sizeof(PROCESS_BASIC_INFORMATION
) /* ProcessBasicInformation */,
3596 sizeof(QUOTA_LIMITS
) /* ProcessQuotaLimits */,
3597 sizeof(IO_COUNTERS
) /* ProcessIoCounters */,
3598 sizeof(VM_COUNTERS
) /* ProcessVmCounters */,
3599 sizeof(KERNEL_USER_TIMES
) /* ProcessTimes */,
3600 sizeof(ULONG
) /* ProcessBasePriority */,
3601 sizeof(ULONG
) /* ProcessRaisePriority */,
3602 sizeof(HANDLE
) /* ProcessDebugPort */,
3603 sizeof(HANDLE
) /* ProcessExceptionPort */,
3604 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3605 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3606 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3607 sizeof(ULONG
) /* ProcessDefaultHardErrorMode */,
3608 0 /* ProcessIoPortHandlers: kernel-mode only */,
3609 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3610 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3611 sizeof(ULONG
) /* ProcessUserModeIOPL */,
3612 sizeof(BOOLEAN
) /* ProcessEnableAlignmentFaultFixup */,
3613 sizeof(PROCESS_PRIORITY_CLASS
) /* ProcessPriorityClass */,
3614 sizeof(ULONG
) /* ProcessWx86Information */,
3615 sizeof(ULONG
) /* ProcessHandleCount */,
3616 sizeof(ULONG_PTR
) /* ProcessAffinityMask */,
3617 sizeof(ULONG
) /* ProcessPriorityBoost */,
3618 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3619 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3620 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3621 sizeof(ULONG_PTR
) /* ProcessWow64Information */,
3622 sizeof(buf
) /* ProcessImageFileName */,
3623 sizeof(ULONG
) /* ProcessLUIDDeviceMapsEnabled */,
3624 sizeof(ULONG
) /* ProcessBreakOnTermination */,
3625 sizeof(HANDLE
) /* ProcessDebugObjectHandle */,
3626 sizeof(ULONG
) /* ProcessDebugFlags */,
3627 sizeof(buf
) /* ProcessHandleTracing */,
3628 sizeof(ULONG
) /* ProcessIoPriority */,
3629 sizeof(ULONG
) /* ProcessExecuteFlags */,
3630 0 /* FIXME: sizeof(?) ProcessTlsInformation */,
3631 0 /* FIXME: sizeof(?) ProcessCookie */,
3632 sizeof(SECTION_IMAGE_INFORMATION
) /* ProcessImageInformation */,
3633 0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */,
3634 sizeof(ULONG
) /* ProcessPagePriority */,
3635 40 /* ProcessInstrumentationCallback */,
3636 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
3637 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
3638 sizeof(buf
) /* ProcessImageFileNameWin32 */,
3639 sizeof(HANDLE
) /* ProcessImageFileMapping */,
3640 0 /* FIXME: sizeof(PROCESS_AFFINITY_UPDATE_MODE) ProcessAffinityUpdateMode */,
3641 0 /* FIXME: sizeof(PROCESS_MEMORY_ALLOCATION_MODE) ProcessMemoryAllocationMode */,
3642 sizeof(USHORT
) /* ProcessGroupInformation */,
3643 sizeof(ULONG
) /* ProcessTokenVirtualizationEnabled */,
3644 sizeof(ULONG_PTR
) /* ProcessConsoleHostProcess */,
3645 0 /* FIXME: sizeof(PROCESS_WINDOW_INFORMATION) ProcessWindowInformation */,
3646 #if 0 /* FIXME: Add remaining classes */
3647 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION
) /* ProcessHandleInformation */,
3648 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION
) /* ProcessMitigationPolicy */,
3649 sizeof(ProcessDynamicFunctionTableInformation
) /* ProcessDynamicFunctionTableInformation */,
3650 sizeof(?) /* ProcessHandleCheckingMode */,
3651 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION
) /* ProcessKeepAliveCount */,
3652 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION
) /* ProcessRevokeFileHandles */,
3653 sizeof(PROCESS_WORKING_SET_CONTROL
) /* ProcessWorkingSetControl */,
3654 sizeof(?) /* ProcessHandleTable */,
3655 sizeof(?) /* ProcessCheckStackExtentsMode */,
3656 sizeof(buf
) /* ProcessCommandLineInformation */,
3657 sizeof(PS_PROTECTION
) /* ProcessProtectionInformation */,
3658 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO
) /* ProcessMemoryExhaustion */,
3659 sizeof(PROCESS_FAULT_INFORMATION
) /* ProcessFaultInformation */,
3660 sizeof(PROCESS_TELEMETRY_ID_INFORMATION
) /* ProcessTelemetryIdInformation */,
3661 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION
) /* ProcessCommitReleaseInformation */,
3662 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3663 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3664 0 /* ProcessReserved1Information */,
3665 0 /* ProcessReserved2Information */,
3666 sizeof(?) /* ProcessSubsystemProcess */,
3667 sizeof(PROCESS_JOB_MEMORY_INFO
) /* ProcessJobMemoryInformation */,
3671 ULONG i
, status
, ret_len
, size
;
3673 if (!pNtQueryInformationProcess
)
3675 win_skip("NtQueryInformationProcess is not available on this platform\n");
3679 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
3682 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
3686 for (i
= 0; i
< MaxProcessInfoClass
; i
++)
3688 size
= info_size
[i
];
3689 if (!size
) size
= sizeof(buf
);
3691 status
= pNtQueryInformationProcess(hproc
, i
, buf
, info_size
[i
], &ret_len
);
3692 if (status
== STATUS_NOT_IMPLEMENTED
) continue;
3693 if (status
== STATUS_INVALID_INFO_CLASS
) continue;
3694 if (status
== STATUS_INFO_LENGTH_MISMATCH
) continue;
3698 case ProcessBasicInformation
:
3699 case ProcessQuotaLimits
:
3701 case ProcessPriorityClass
:
3702 case ProcessPriorityBoost
:
3703 case ProcessLUIDDeviceMapsEnabled
:
3704 case 33 /* ProcessIoPriority */:
3705 case ProcessIoCounters
:
3706 case ProcessVmCounters
:
3707 case ProcessWow64Information
:
3708 case ProcessDefaultHardErrorMode
:
3709 case ProcessHandleCount
:
3710 case ProcessImageFileName
:
3711 case ProcessImageInformation
:
3712 case ProcessPagePriority
:
3713 case ProcessImageFileNameWin32
:
3714 ok(status
== STATUS_SUCCESS
, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3717 case ProcessAffinityMask
:
3718 case ProcessBreakOnTermination
:
3719 case ProcessGroupInformation
:
3720 case ProcessConsoleHostProcess
:
3721 ok(status
== STATUS_ACCESS_DENIED
/* before win8 */ || status
== STATUS_SUCCESS
/* win8 is less strict */,
3722 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3725 case ProcessDebugObjectHandle
:
3726 ok(status
== STATUS_ACCESS_DENIED
|| status
== STATUS_PORT_NOT_SET
,
3727 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3730 case ProcessExecuteFlags
:
3731 case ProcessDebugPort
:
3732 case ProcessDebugFlags
:
3735 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3739 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3747 static void test_GetLogicalProcessorInformationEx(void)
3749 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*info
;
3753 if (!pGetLogicalProcessorInformationEx
)
3755 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3759 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, NULL
);
3760 ok(!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "got %d, error %d\n", ret
, GetLastError());
3763 ret
= pGetLogicalProcessorInformationEx(RelationProcessorCore
, NULL
, &len
);
3764 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %d\n", ret
, GetLastError());
3765 ok(len
> 0, "got %u\n", len
);
3768 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, &len
);
3769 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %d\n", ret
, GetLastError());
3770 ok(len
> 0, "got %u\n", len
);
3772 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
3773 ret
= pGetLogicalProcessorInformationEx(RelationAll
, info
, &len
);
3774 ok(ret
, "got %d, error %d\n", ret
, GetLastError());
3775 ok(info
->Size
> 0, "got %u\n", info
->Size
);
3776 HeapFree(GetProcessHeap(), 0, info
);
3779 static void test_largepages(void)
3783 if (!pGetLargePageMinimum
) {
3784 skip("No GetLargePageMinimum support.\n");
3787 size
= pGetLargePageMinimum();
3789 ok((size
== 0) || (size
== 2*1024*1024) || (size
== 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size
);
3792 struct proc_thread_attr
3799 struct _PROC_THREAD_ATTRIBUTE_LIST
3801 DWORD mask
; /* bitmask of items in list */
3802 DWORD size
; /* max number of items in list */
3803 DWORD count
; /* number of items in list */
3806 struct proc_thread_attr attrs
[10];
3809 static void test_ProcThreadAttributeList(void)
3812 SIZE_T size
, needed
;
3814 struct _PROC_THREAD_ATTRIBUTE_LIST list
, expect_list
;
3817 if (!pInitializeProcThreadAttributeList
)
3819 win_skip("No support for ProcThreadAttributeList\n");
3823 for (i
= 0; i
<= 10; i
++)
3825 needed
= FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST
, attrs
[i
]);
3826 ret
= pInitializeProcThreadAttributeList(NULL
, i
, 0, &size
);
3827 ok(!ret
, "got %d\n", ret
);
3828 if(i
>= 4 && GetLastError() == ERROR_INVALID_PARAMETER
) /* Vista only allows a maximium of 3 slots */
3830 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d\n", GetLastError());
3831 ok(size
== needed
, "%d: got %ld expect %ld\n", i
, size
, needed
);
3833 memset(&list
, 0xcc, sizeof(list
));
3834 ret
= pInitializeProcThreadAttributeList(&list
, i
, 0, &size
);
3835 ok(ret
, "got %d\n", ret
);
3836 ok(list
.mask
== 0, "%d: got %08x\n", i
, list
.mask
);
3837 ok(list
.size
== i
, "%d: got %08x\n", i
, list
.size
);
3838 ok(list
.count
== 0, "%d: got %08x\n", i
, list
.count
);
3839 ok(list
.unk
== 0, "%d: got %08lx\n", i
, list
.unk
);
3842 memset(handles
, 0, sizeof(handles
));
3843 memset(&expect_list
, 0xcc, sizeof(expect_list
));
3844 expect_list
.mask
= 0;
3845 expect_list
.size
= i
- 1;
3846 expect_list
.count
= 0;
3847 expect_list
.unk
= 0;
3849 ret
= pUpdateProcThreadAttribute(&list
, 0, 0xcafe, handles
, sizeof(PROCESSOR_NUMBER
), NULL
, NULL
);
3850 ok(!ret
, "got %d\n", ret
);
3851 ok(GetLastError() == ERROR_NOT_SUPPORTED
, "got %d\n", GetLastError());
3853 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]) / 2, NULL
, NULL
);
3854 ok(!ret
, "got %d\n", ret
);
3855 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %d\n", GetLastError());
3857 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]) * 2, NULL
, NULL
);
3858 ok(!ret
, "got %d\n", ret
);
3859 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %d\n", GetLastError());
3861 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]), NULL
, NULL
);
3862 ok(ret
, "got %d\n", ret
);
3864 expect_list
.mask
|= 1 << ProcThreadAttributeParentProcess
;
3865 expect_list
.attrs
[0].attr
= PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
;
3866 expect_list
.attrs
[0].size
= sizeof(handles
[0]);
3867 expect_list
.attrs
[0].value
= handles
;
3868 expect_list
.count
++;
3870 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]), NULL
, NULL
);
3871 ok(!ret
, "got %d\n", ret
);
3872 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS
, "got %d\n", GetLastError());
3874 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
) - 1, NULL
, NULL
);
3875 ok(!ret
, "got %d\n", ret
);
3876 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %d\n", GetLastError());
3878 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
), NULL
, NULL
);
3879 ok(ret
, "got %d\n", ret
);
3881 expect_list
.mask
|= 1 << ProcThreadAttributeHandleList
;
3882 expect_list
.attrs
[1].attr
= PROC_THREAD_ATTRIBUTE_HANDLE_LIST
;
3883 expect_list
.attrs
[1].size
= sizeof(handles
);
3884 expect_list
.attrs
[1].value
= handles
;
3885 expect_list
.count
++;
3887 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
), NULL
, NULL
);
3888 ok(!ret
, "got %d\n", ret
);
3889 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS
, "got %d\n", GetLastError());
3891 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR
, handles
, sizeof(PROCESSOR_NUMBER
), NULL
, NULL
);
3892 ok(ret
|| GetLastError() == ERROR_NOT_SUPPORTED
, "got %d gle %d\n", ret
, GetLastError());
3896 expect_list
.mask
|= 1 << ProcThreadAttributeIdealProcessor
;
3897 expect_list
.attrs
[2].attr
= PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR
;
3898 expect_list
.attrs
[2].size
= sizeof(PROCESSOR_NUMBER
);
3899 expect_list
.attrs
[2].value
= handles
;
3900 expect_list
.count
++;
3903 ok(!memcmp(&list
, &expect_list
, size
), "mismatch\n");
3905 pDeleteProcThreadAttributeList(&list
);
3908 static void test_GetActiveProcessorCount(void)
3912 if (!pGetActiveProcessorCount
)
3914 win_skip("GetActiveProcessorCount not available, skipping test\n");
3918 count
= pGetActiveProcessorCount(0);
3919 ok(count
, "GetActiveProcessorCount failed, error %u\n", GetLastError());
3921 /* Test would fail on systems with more than 6400 processors */
3922 SetLastError(0xdeadbeef);
3923 count
= pGetActiveProcessorCount(101);
3924 ok(count
== 0, "Expeced GetActiveProcessorCount to fail\n");
3925 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3932 ok(b
, "Basic init of CreateProcess test\n");
3937 if (!strcmp(myARGV
[2], "dump") && myARGC
>= 4)
3939 doChild(myARGV
[3], (myARGC
>= 5) ? myARGV
[4] : NULL
);
3942 else if (!strcmp(myARGV
[2], "wait"))
3945 ok(0, "Child process not killed\n");
3948 else if (!strcmp(myARGV
[2], "exit"))
3953 else if (!strcmp(myARGV
[2], "nested") && myARGC
>= 4)
3955 char buffer
[MAX_PATH
];
3956 STARTUPINFOA startup
;
3957 PROCESS_INFORMATION info
;
3959 memset(&startup
, 0, sizeof(startup
));
3960 startup
.cb
= sizeof(startup
);
3961 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3962 startup
.wShowWindow
= SW_SHOWNORMAL
;
3964 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, myARGV
[3]);
3965 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
3966 CloseHandle(info
.hProcess
);
3967 CloseHandle(info
.hThread
);
3971 ok(0, "Unexpected command %s\n", myARGV
[2]);
3975 test_process_info();
3976 test_TerminateProcess();
3983 test_DebuggingFlag();
3987 test_GetProcessVersion();
3988 test_GetProcessImageFileNameA();
3989 test_QueryFullProcessImageNameA();
3990 test_QueryFullProcessImageNameW();
3992 test_IsWow64Process();
3994 test_RegistryQuota();
3995 test_DuplicateHandle();
3996 test_StartupNoConsole();
3997 test_DetachConsoleHandles();
3998 test_DetachStdHandles();
3999 test_GetNumaProcessorNode();
4000 test_session_info();
4001 test_GetLogicalProcessorInformationEx();
4002 test_GetActiveProcessorCount();
4004 test_ProcThreadAttributeList();
4005 test_SuspendProcessState();
4006 test_SuspendProcessNewThread();
4008 /* things that can be tested:
4009 * lookup: check the way program to be executed is searched
4010 * handles: check the handle inheritance stuff (+sec options)
4011 * console: check if console creation parameters work
4014 if (!pCreateJobObjectW
)
4016 win_skip("No job object support\n");
4020 test_IsProcessInJob();
4021 test_TerminateJobObject();
4022 test_QueryInformationJobObject();
4023 test_CompletionPort();
4024 test_KillOnJobClose();
4025 test_WaitForJobObject();
4026 job
= test_AddSelfToJob();
4027 test_jobInheritance(job
);
4028 test_BreakawayOk(job
);