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 memset(&startup
, 0, sizeof(startup
));
1152 startup
.cb
= sizeof(startup
);
1153 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1154 startup
.wShowWindow
= SW_SHOWNORMAL
;
1156 get_file_name(resfile
);
1157 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1158 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1159 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1160 CloseHandle(info
.hProcess
);
1161 CloseHandle(info
.hThread
);
1163 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1164 okChildInt("Toolhelp", "cntUsage", 0);
1165 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1166 okChildInt("Toolhelp", "th32ModuleID", 0);
1167 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1168 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1169 okChildInt("Toolhelp", "dwFlags", 0);
1172 DeleteFileA(resfile
);
1174 get_file_name(resfile
);
1175 sprintf(buffer
, "\"%s\" tests/process.c nested \"%s\"", selfname
, resfile
);
1176 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1177 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1179 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1180 ok(process
!= NULL
, "OpenProcess failed %u\n", GetLastError());
1181 CloseHandle(process
);
1183 CloseHandle(info
.hProcess
);
1184 CloseHandle(info
.hThread
);
1186 for (i
= 0; i
< 20; i
++)
1188 SetLastError(0xdeadbeef);
1189 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1190 ok(process
|| GetLastError() == ERROR_INVALID_PARAMETER
, "OpenProcess failed %u\n", GetLastError());
1191 if (!process
) break;
1192 CloseHandle(process
);
1195 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1196 ok(i
< 20 || broken(i
== 20), "process object not released\n");
1198 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
1199 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1200 memset(&pe
, 0, sizeof(pe
));
1201 pe
.dwSize
= sizeof(pe
);
1202 if (pProcess32First(snapshot
, &pe
))
1204 while (pe
.th32ParentProcessID
!= info
.dwProcessId
)
1205 if (!pProcess32Next(snapshot
, &pe
)) break;
1207 CloseHandle(snapshot
);
1208 ok(pe
.th32ParentProcessID
== info
.dwProcessId
, "failed to find nested child process\n");
1210 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, pe
.th32ProcessID
);
1211 ok(process
!= NULL
, "OpenProcess failed %u\n", GetLastError());
1213 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD
, 0);
1214 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1215 memset(&te
, 0, sizeof(te
));
1216 te
.dwSize
= sizeof(te
);
1217 if (pThread32First(snapshot
, &te
))
1219 while (te
.th32OwnerProcessID
!= pe
.th32ProcessID
)
1220 if (!pThread32Next(snapshot
, &te
)) break;
1222 CloseHandle(snapshot
);
1223 ok(te
.th32OwnerProcessID
== pe
.th32ProcessID
, "failed to find suspended thread\n");
1225 thread
= OpenThread(THREAD_ALL_ACCESS_NT4
, FALSE
, te
.th32ThreadID
);
1226 ok(thread
!= NULL
, "OpenThread failed %u\n", GetLastError());
1227 ret
= ResumeThread(thread
);
1228 ok(ret
== 1, "expected 1, got %u\n", ret
);
1229 CloseHandle(thread
);
1231 ok(WaitForSingleObject(process
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1232 CloseHandle(process
);
1234 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1235 okChildInt("Toolhelp", "cntUsage", 0);
1236 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1237 okChildInt("Toolhelp", "th32ModuleID", 0);
1238 okChildInt("Toolhelp", "th32ParentProcessID", info
.dwProcessId
);
1239 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1240 okChildInt("Toolhelp", "dwFlags", 0);
1243 DeleteFileA(resfile
);
1246 static BOOL
is_str_env_drive_dir(const char* str
)
1248 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1249 str
[3] == '=' && str
[4] == str
[1];
1252 /* compared expected child's environment (in gesA) from actual
1253 * environment our child got
1255 static void cmpEnvironment(const char* gesA
)
1263 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1265 /* now look each parent env in child */
1266 if ((ptrA
= gesA
) != NULL
)
1270 for (i
= 0; i
< clen
; i
++)
1272 sprintf(key
, "env%d", i
);
1273 res
= getChildString("EnvironmentA", key
);
1274 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1278 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1280 ptrA
+= strlen(ptrA
) + 1;
1284 /* and each child env in parent */
1285 for (i
= 0; i
< clen
; i
++)
1287 sprintf(key
, "env%d", i
);
1288 res
= getChildString("EnvironmentA", key
);
1289 if ((ptrA
= gesA
) != NULL
)
1293 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1295 ptrA
+= strlen(ptrA
) + 1;
1297 if (!*ptrA
) ptrA
= NULL
;
1300 if (!is_str_env_drive_dir(res
))
1302 found
= ptrA
!= NULL
;
1303 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1305 /* else => should also test we get the right per drive default directory here... */
1309 static void test_Environment(void)
1311 char buffer
[MAX_PATH
];
1312 PROCESS_INFORMATION info
;
1313 STARTUPINFOA startup
;
1321 memset(&startup
, 0, sizeof(startup
));
1322 startup
.cb
= sizeof(startup
);
1323 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1324 startup
.wShowWindow
= SW_SHOWNORMAL
;
1327 get_file_name(resfile
);
1328 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1329 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1330 /* wait for child to terminate */
1331 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1332 /* child process has changed result file, so let profile functions know about it */
1333 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1335 env
= GetEnvironmentStringsA();
1336 cmpEnvironment(env
);
1338 DeleteFileA(resfile
);
1340 memset(&startup
, 0, sizeof(startup
));
1341 startup
.cb
= sizeof(startup
);
1342 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1343 startup
.wShowWindow
= SW_SHOWNORMAL
;
1346 get_file_name(resfile
);
1347 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1353 slen
= strlen(ptr
)+1;
1354 child_env_len
+= slen
;
1357 /* Add space for additional environment variables */
1358 child_env_len
+= 256;
1359 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1362 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1363 ptr
+= strlen(ptr
) + 1;
1364 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1365 ptr
+= strlen(ptr
) + 1;
1366 strcpy(ptr
, "FOO=BAR");
1367 ptr
+= strlen(ptr
) + 1;
1368 strcpy(ptr
, "BAR=FOOBAR");
1369 ptr
+= strlen(ptr
) + 1;
1370 /* copy all existing variables except:
1372 * - PATH (already set above)
1373 * - the directory definitions (=[A-Z]:=)
1375 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1377 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1378 strncmp(ptr2
, "WINELOADER=", 11) != 0 &&
1379 !is_str_env_drive_dir(ptr2
))
1382 ptr
+= strlen(ptr
) + 1;
1386 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1387 /* wait for child to terminate */
1388 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1389 /* child process has changed result file, so let profile functions know about it */
1390 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1392 cmpEnvironment(child_env
);
1394 HeapFree(GetProcessHeap(), 0, child_env
);
1395 FreeEnvironmentStringsA(env
);
1397 DeleteFileA(resfile
);
1400 static void test_SuspendFlag(void)
1402 char buffer
[MAX_PATH
];
1403 PROCESS_INFORMATION info
;
1404 STARTUPINFOA startup
, us
;
1408 /* let's start simplistic */
1409 memset(&startup
, 0, sizeof(startup
));
1410 startup
.cb
= sizeof(startup
);
1411 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1412 startup
.wShowWindow
= SW_SHOWNORMAL
;
1414 get_file_name(resfile
);
1415 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1416 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1418 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1420 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1421 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1423 /* wait for child to terminate */
1424 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1425 /* child process has changed result file, so let profile functions know about it */
1426 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1428 GetStartupInfoA(&us
);
1430 okChildInt("StartupInfoA", "cb", startup
.cb
);
1431 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1432 result
= getChildString( "StartupInfoA", "lpTitle" );
1433 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1434 "expected '%s' or null, got '%s'\n", selfname
, result
);
1435 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1436 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1437 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1438 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1439 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1440 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1441 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1442 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1443 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1445 DeleteFileA(resfile
);
1448 static void test_DebuggingFlag(void)
1450 char buffer
[MAX_PATH
];
1451 void *processbase
= NULL
;
1452 PROCESS_INFORMATION info
;
1453 STARTUPINFOA startup
, us
;
1458 /* let's start simplistic */
1459 memset(&startup
, 0, sizeof(startup
));
1460 startup
.cb
= sizeof(startup
);
1461 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1462 startup
.wShowWindow
= SW_SHOWNORMAL
;
1464 get_file_name(resfile
);
1465 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1466 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1468 /* get all startup events up to the entry point break exception */
1471 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1472 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1475 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1476 "first event: %d\n", de
.dwDebugEventCode
);
1477 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1479 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1480 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1481 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1482 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1484 ok(dbg
, "I have seen a debug event\n");
1485 /* wait for child to terminate */
1486 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1487 /* child process has changed result file, so let profile functions know about it */
1488 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1490 GetStartupInfoA(&us
);
1492 okChildInt("StartupInfoA", "cb", startup
.cb
);
1493 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1494 result
= getChildString( "StartupInfoA", "lpTitle" );
1495 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1496 "expected '%s' or null, got '%s'\n", selfname
, result
);
1497 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1498 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1499 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1500 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1501 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1502 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1503 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1504 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1505 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1507 DeleteFileA(resfile
);
1510 static BOOL
is_console(HANDLE h
)
1512 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1515 static void test_Console(void)
1517 char buffer
[MAX_PATH
];
1518 PROCESS_INFORMATION info
;
1519 STARTUPINFOA startup
, us
;
1520 SECURITY_ATTRIBUTES sa
;
1521 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1522 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1523 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1525 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1526 const char* msg
= "This is a std-handle inheritance test.";
1528 BOOL run_tests
= TRUE
;
1531 memset(&startup
, 0, sizeof(startup
));
1532 startup
.cb
= sizeof(startup
);
1533 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1534 startup
.wShowWindow
= SW_SHOWNORMAL
;
1536 sa
.nLength
= sizeof(sa
);
1537 sa
.lpSecurityDescriptor
= NULL
;
1538 sa
.bInheritHandle
= TRUE
;
1540 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1541 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1543 /* first, we need to be sure we're attached to a console */
1544 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1546 /* we're not attached to a console, let's do it */
1548 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1549 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1551 /* now verify everything's ok */
1552 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1553 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1554 startup
.hStdError
= startup
.hStdOutput
;
1556 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1557 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
), "Getting console in mode\n");
1558 ok(GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console out mode\n");
1559 cpIn
= GetConsoleCP();
1560 cpOut
= GetConsoleOutputCP();
1562 get_file_name(resfile
);
1563 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" console", selfname
, resfile
);
1564 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1566 /* wait for child to terminate */
1567 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1568 /* child process has changed result file, so let profile functions know about it */
1569 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1571 /* now get the modification the child has made, and resets parents expected values */
1572 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1573 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
), "Getting console in mode\n");
1574 ok(GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console out mode\n");
1576 SetConsoleMode(startup
.hStdInput
, modeIn
);
1577 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1579 cpInC
= GetConsoleCP();
1580 cpOutC
= GetConsoleOutputCP();
1582 /* Try to set invalid CP */
1583 SetLastError(0xdeadbeef);
1584 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1585 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1586 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1587 "GetLastError: expecting %u got %u\n",
1588 ERROR_INVALID_PARAMETER
, GetLastError());
1589 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1593 SetLastError(0xdeadbeef);
1594 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1595 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1596 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1597 "GetLastError: expecting %u got %u\n",
1598 ERROR_INVALID_PARAMETER
, GetLastError());
1601 SetConsoleOutputCP(cpOut
);
1603 GetStartupInfoA(&us
);
1605 okChildInt("StartupInfoA", "cb", startup
.cb
);
1606 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1607 result
= getChildString( "StartupInfoA", "lpTitle" );
1608 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1609 "expected '%s' or null, got '%s'\n", selfname
, result
);
1610 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1611 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1612 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1613 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1614 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1615 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1616 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1617 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1618 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1620 /* check child correctly inherited the console */
1621 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1622 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1623 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1624 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1625 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1626 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1627 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1628 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1629 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1630 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1631 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1632 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1633 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1634 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1635 okChildInt("Console", "InputCP", cpIn
);
1636 okChildInt("Console", "OutputCP", cpOut
);
1637 okChildInt("Console", "InputMode", modeIn
);
1638 okChildInt("Console", "OutputMode", modeOut
);
1642 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1643 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1646 win_skip("Setting the codepage is not implemented\n");
1648 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1649 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1650 trace("cursor position(X): %d/%d\n",sbi
.dwCursorPosition
.X
, sbiC
.dwCursorPosition
.X
);
1651 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1654 DeleteFileA(resfile
);
1656 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1657 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1658 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1659 "Duplicating as inheritable child-output pipe\n");
1660 CloseHandle(hChildOut
);
1662 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1663 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1664 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1665 "Duplicating as inheritable child-input pipe\n");
1666 CloseHandle(hChildIn
);
1668 memset(&startup
, 0, sizeof(startup
));
1669 startup
.cb
= sizeof(startup
);
1670 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1671 startup
.wShowWindow
= SW_SHOWNORMAL
;
1672 startup
.hStdInput
= hChildInInh
;
1673 startup
.hStdOutput
= hChildOutInh
;
1674 startup
.hStdError
= hChildOutInh
;
1676 get_file_name(resfile
);
1677 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname
, resfile
);
1678 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1679 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1680 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1682 msg_len
= strlen(msg
) + 1;
1683 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1684 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1685 memset(buffer
, 0, sizeof(buffer
));
1686 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1687 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1689 /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1690 ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
);
1692 /* wait for child to terminate */
1693 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1694 /* child process has changed result file, so let profile functions know about it */
1695 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1697 okChildString("StdHandle", "msg", msg
);
1700 DeleteFileA(resfile
);
1703 static void test_ExitCode(void)
1705 char buffer
[MAX_PATH
];
1706 PROCESS_INFORMATION info
;
1707 STARTUPINFOA startup
;
1710 /* let's start simplistic */
1711 memset(&startup
, 0, sizeof(startup
));
1712 startup
.cb
= sizeof(startup
);
1713 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1714 startup
.wShowWindow
= SW_SHOWNORMAL
;
1716 get_file_name(resfile
);
1717 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname
, resfile
);
1718 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1720 /* wait for child to terminate */
1721 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1722 /* child process has changed result file, so let profile functions know about it */
1723 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1725 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1726 okChildInt("ExitCode", "value", code
);
1729 DeleteFileA(resfile
);
1732 static void test_OpenProcess(void)
1736 MEMORY_BASIC_INFORMATION info
;
1737 SIZE_T dummy
, read_bytes
;
1740 /* not exported in all windows versions */
1741 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1742 win_skip("VirtualAllocEx not found\n");
1746 /* without PROCESS_VM_OPERATION */
1747 hproc
= OpenProcess(PROCESS_ALL_ACCESS_NT4
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1748 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1750 SetLastError(0xdeadbeef);
1751 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1752 ok(!addr1
, "VirtualAllocEx should fail\n");
1753 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1756 win_skip("VirtualAllocEx not implemented\n");
1759 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1761 read_bytes
= 0xdeadbeef;
1762 SetLastError(0xdeadbeef);
1763 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1764 ok(ret
, "ReadProcessMemory error %d\n", GetLastError());
1765 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1769 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1770 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1772 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1773 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1775 /* without PROCESS_QUERY_INFORMATION */
1776 SetLastError(0xdeadbeef);
1777 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1778 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1779 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1781 /* without PROCESS_VM_READ */
1782 read_bytes
= 0xdeadbeef;
1783 SetLastError(0xdeadbeef);
1784 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1785 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1786 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1787 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1791 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1793 memset(&info
, 0xcc, sizeof(info
));
1794 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1795 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1797 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1798 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1799 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1800 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1801 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1802 /* NT reports Protect == 0 for a not committed memory block */
1803 ok(info
.Protect
== 0 /* NT */ ||
1804 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1805 "%x != PAGE_NOACCESS\n", info
.Protect
);
1806 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1808 SetLastError(0xdeadbeef);
1809 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1810 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1811 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1815 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
1818 SetLastError(0xdeadbeef);
1819 memset(&info
, 0xcc, sizeof(info
));
1820 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1821 if (read_bytes
) /* win8 */
1823 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1824 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1825 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1826 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1827 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1828 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1829 ok(info
.Protect
== 0, "%x != PAGE_NOACCESS\n", info
.Protect
);
1830 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1832 else /* before win8 */
1833 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1835 SetLastError(0xdeadbeef);
1836 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1837 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1838 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1843 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1846 static void test_GetProcessVersion(void)
1848 static char cmdline
[] = "winver.exe";
1849 PROCESS_INFORMATION pi
;
1853 SetLastError(0xdeadbeef);
1854 ret
= GetProcessVersion(0);
1855 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1857 SetLastError(0xdeadbeef);
1858 ret
= GetProcessVersion(GetCurrentProcessId());
1859 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1861 memset(&si
, 0, sizeof(si
));
1863 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1864 si
.wShowWindow
= SW_HIDE
;
1865 SetLastError(0xdeadbeef);
1866 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1867 ok(ret
, "CreateProcess error %u\n", GetLastError());
1869 SetLastError(0xdeadbeef);
1870 ret
= GetProcessVersion(pi
.dwProcessId
);
1871 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1873 SetLastError(0xdeadbeef);
1874 ret
= TerminateProcess(pi
.hProcess
, 0);
1875 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1877 CloseHandle(pi
.hProcess
);
1878 CloseHandle(pi
.hThread
);
1881 static void test_GetProcessImageFileNameA(void)
1884 CHAR process
[MAX_PATH
];
1885 static const char harddisk
[] = "\\Device\\HarddiskVolume";
1887 if (!pK32GetProcessImageFileNameA
)
1889 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1893 /* callers must guess the buffer size */
1894 SetLastError(0xdeadbeef);
1895 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL
, 0);
1896 ok(!rc
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
1897 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc
, GetLastError());
1900 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), process
, sizeof(process
));
1901 expect_eq_d(rc
, lstrlenA(process
));
1902 if (strncmp(process
, harddisk
, lstrlenA(harddisk
)))
1904 todo_wine
win_skip("%s is probably on a network share, skipping tests\n", process
);
1908 if (!pQueryFullProcessImageNameA
)
1909 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1912 CHAR image
[MAX_PATH
];
1915 length
= sizeof(image
);
1916 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE
, image
, &length
));
1917 expect_eq_d(length
, lstrlenA(image
));
1918 ok(lstrcmpiA(process
, image
) == 0, "expected '%s' to be equal to '%s'\n", process
, image
);
1922 static void test_QueryFullProcessImageNameA(void)
1924 #define INIT_STR "Just some words"
1926 CHAR buf
[MAX_PATH
], module
[MAX_PATH
];
1928 if (!pQueryFullProcessImageNameA
)
1930 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1935 SetLastError(0); /* old Windows don't reset it on success */
1936 size
= GetModuleFileNameA(NULL
, module
, sizeof(module
));
1937 ok(size
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
, "GetModuleFileName failed: %u le=%u\n", size
, GetLastError());
1939 /* get the buffer length without \0 terminator */
1940 length
= sizeof(buf
);
1941 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1942 expect_eq_d(length
, lstrlenA(buf
));
1943 ok((buf
[0] == '\\' && buf
[1] == '\\') ||
1944 lstrcmpiA(buf
, module
) == 0, "expected %s to match %s\n", buf
, module
);
1946 /* when the buffer is too small
1947 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1948 * - the size variable is not modified
1949 * tested with the biggest too small size
1952 sprintf(buf
,INIT_STR
);
1953 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1954 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1955 expect_eq_d(length
, size
);
1956 expect_eq_s(INIT_STR
, buf
);
1958 /* retest with smaller buffer size
1961 sprintf(buf
,INIT_STR
);
1962 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1963 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1964 expect_eq_d(4, size
);
1965 expect_eq_s(INIT_STR
, buf
);
1967 /* this is a difference between the ascii and the unicode version
1968 * the unicode version crashes when the size is big enough to hold
1969 * the result while the ascii version throws an error
1972 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1973 expect_eq_d(1024, size
);
1974 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1977 static void test_QueryFullProcessImageNameW(void)
1980 WCHAR module_name
[1024], device
[1024];
1981 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
1985 if (!pQueryFullProcessImageNameW
)
1987 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1991 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1993 /* GetCurrentProcess pseudo-handle */
1994 size
= sizeof(buf
) / sizeof(buf
[0]);
1995 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
1996 expect_eq_d(lstrlenW(buf
), size
);
1997 expect_eq_ws_i(buf
, module_name
);
1999 hSelf
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
2001 size
= sizeof(buf
) / sizeof(buf
[0]);
2002 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
2003 expect_eq_d(lstrlenW(buf
), size
);
2004 expect_eq_ws_i(buf
, module_name
);
2006 /* Buffer too small */
2007 size
= lstrlenW(module_name
)/2;
2008 lstrcpyW(buf
, deviceW
);
2009 SetLastError(0xdeadbeef);
2010 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
2011 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
2012 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2013 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
2015 /* Too small - not space for NUL terminator */
2016 size
= lstrlenW(module_name
);
2017 SetLastError(0xdeadbeef);
2018 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
2019 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
2020 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2024 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
2025 expect_eq_d(0, size
);
2026 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2028 /* Buffer too small */
2029 size
= lstrlenW(module_name
)/2;
2030 SetLastError(0xdeadbeef);
2031 lstrcpyW(buf
, module_name
);
2032 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
2033 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
2034 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2035 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
2039 size
= sizeof(buf
) / sizeof(buf
[0]);
2040 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
2041 expect_eq_d(lstrlenW(buf
), size
);
2042 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
2043 ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
2045 module_name
[2] = '\0';
2047 size
= QueryDosDeviceW(module_name
, device
, sizeof(device
)/sizeof(device
[0]));
2048 ok(size
, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2049 len
= lstrlenW(device
);
2050 ok(size
>= len
+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size
, len
, wine_dbgstr_w(device
));
2052 if (size
>= lstrlenW(buf
))
2054 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2058 ok(buf
[len
] == '\\', "expected '%c' to be a '\\' in %s\n", buf
[len
], wine_dbgstr_w(module_name
));
2060 ok(lstrcmpiW(device
, buf
) == 0, "expected %s to match %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2061 ok(lstrcmpiW(module_name
+3, buf
+len
+1) == 0, "expected '%s' to match '%s'\n", wine_dbgstr_w(module_name
+3), wine_dbgstr_w(buf
+len
+1));
2067 static void test_Handles(void)
2069 HANDLE handle
= GetCurrentProcess();
2074 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
2075 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
2076 "invalid current process handle %p\n", handle
);
2077 ret
= GetExitCodeProcess( handle
, &code
);
2078 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
2080 /* truncated handle */
2081 SetLastError( 0xdeadbeef );
2082 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
2083 ret
= GetExitCodeProcess( handle
, &code
);
2084 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2085 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
2086 /* sign-extended handle */
2087 SetLastError( 0xdeadbeef );
2088 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
2089 ret
= GetExitCodeProcess( handle
, &code
);
2090 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
2091 /* invalid high-word */
2092 SetLastError( 0xdeadbeef );
2093 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
2094 ret
= GetExitCodeProcess( handle
, &code
);
2095 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2096 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
2099 handle
= GetStdHandle( STD_ERROR_HANDLE
);
2100 ok( handle
!= 0, "handle %p\n", handle
);
2101 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
2102 0, TRUE
, DUPLICATE_SAME_ACCESS
);
2103 SetStdHandle( STD_ERROR_HANDLE
, h3
);
2104 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
2105 h2
= GetStdHandle( STD_ERROR_HANDLE
);
2107 broken( h2
== h3
) || /* nt4, w2k */
2108 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
2109 "wrong handle %p/%p\n", h2
, h3
);
2110 SetStdHandle( STD_ERROR_HANDLE
, handle
);
2113 static void test_IsWow64Process(void)
2115 PROCESS_INFORMATION pi
;
2119 static char cmdline
[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2120 static char cmdline_wow64
[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2122 if (!pIsWow64Process
)
2124 skip("IsWow64Process is not available\n");
2128 memset(&si
, 0, sizeof(si
));
2130 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2131 si
.wShowWindow
= SW_HIDE
;
2132 ret
= CreateProcessA(NULL
, cmdline_wow64
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2135 trace("Created process %s\n", cmdline_wow64
);
2137 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2138 ok(ret
, "IsWow64Process failed.\n");
2139 ok(is_wow64
, "is_wow64 returned FALSE.\n");
2141 ret
= TerminateProcess(pi
.hProcess
, 0);
2142 ok(ret
, "TerminateProcess error\n");
2144 CloseHandle(pi
.hProcess
);
2145 CloseHandle(pi
.hThread
);
2148 memset(&si
, 0, sizeof(si
));
2150 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2151 si
.wShowWindow
= SW_HIDE
;
2152 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2155 trace("Created process %s\n", cmdline
);
2157 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2158 ok(ret
, "IsWow64Process failed.\n");
2159 ok(!is_wow64
, "is_wow64 returned TRUE.\n");
2161 ret
= TerminateProcess(pi
.hProcess
, 0);
2162 ok(ret
, "TerminateProcess error\n");
2164 CloseHandle(pi
.hProcess
);
2165 CloseHandle(pi
.hThread
);
2169 static void test_SystemInfo(void)
2171 SYSTEM_INFO si
, nsi
;
2174 if (!pGetNativeSystemInfo
)
2176 win_skip("GetNativeSystemInfo is not available\n");
2180 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
2183 pGetNativeSystemInfo(&nsi
);
2186 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
2188 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
2189 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2190 S(U(nsi
)).wProcessorArchitecture
);
2191 ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
,
2192 "Expected PROCESSOR_AMD_X8664, got %d\n",
2193 nsi
.dwProcessorType
);
2198 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
2199 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2200 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
2201 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
2202 "Expected no difference for dwProcessorType, got %d and %d\n",
2203 si
.dwProcessorType
, nsi
.dwProcessorType
);
2207 static void test_RegistryQuota(void)
2210 DWORD max_quota
, used_quota
;
2212 if (!pGetSystemRegistryQuota
)
2214 win_skip("GetSystemRegistryQuota is not available\n");
2218 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
2220 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2222 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
2224 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2226 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
2228 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2230 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
2232 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2235 static void test_TerminateProcess(void)
2237 static char cmdline
[] = "winver.exe";
2238 PROCESS_INFORMATION pi
;
2241 HANDLE dummy
, thread
;
2243 memset(&si
, 0, sizeof(si
));
2245 SetLastError(0xdeadbeef);
2246 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2247 ok(ret
, "CreateProcess error %u\n", GetLastError());
2249 SetLastError(0xdeadbeef);
2250 thread
= CreateRemoteThread(pi
.hProcess
, NULL
, 0, (void *)0xdeadbeef, NULL
, CREATE_SUSPENDED
, &ret
);
2251 ok(thread
!= 0, "CreateRemoteThread error %d\n", GetLastError());
2253 /* create a not closed thread handle duplicate in the target process */
2254 SetLastError(0xdeadbeef);
2255 ret
= DuplicateHandle(GetCurrentProcess(), thread
, pi
.hProcess
, &dummy
,
2256 0, FALSE
, DUPLICATE_SAME_ACCESS
);
2257 ok(ret
, "DuplicateHandle error %u\n", GetLastError());
2259 SetLastError(0xdeadbeef);
2260 ret
= TerminateThread(thread
, 0);
2261 ok(ret
, "TerminateThread error %u\n", GetLastError());
2262 CloseHandle(thread
);
2264 SetLastError(0xdeadbeef);
2265 ret
= TerminateProcess(pi
.hProcess
, 0);
2266 ok(ret
, "TerminateProcess error %u\n", GetLastError());
2268 CloseHandle(pi
.hProcess
);
2269 CloseHandle(pi
.hThread
);
2272 static void test_DuplicateHandle(void)
2274 char path
[MAX_PATH
], file_name
[MAX_PATH
];
2275 HANDLE f
, fmin
, out
;
2279 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2280 GetCurrentProcess(), &out
, 0, FALSE
,
2281 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2282 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2283 r
= GetHandleInformation(out
, &info
);
2284 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2285 ok(info
== 0, "info = %x\n", info
);
2286 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2289 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2290 GetCurrentProcess(), &out
, 0, TRUE
,
2291 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2292 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2293 r
= GetHandleInformation(out
, &info
);
2294 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2295 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2296 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2299 GetTempPathA(MAX_PATH
, path
);
2300 GetTempFileNameA(path
, "wt", 0, file_name
);
2301 f
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
2302 if (f
== INVALID_HANDLE_VALUE
)
2304 ok(0, "could not create %s\n", file_name
);
2308 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2309 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2310 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2311 ok(f
== out
, "f != out\n");
2312 r
= GetHandleInformation(out
, &info
);
2313 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2314 ok(info
== 0, "info = %x\n", info
);
2316 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2317 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2318 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2319 ok(f
== out
, "f != out\n");
2320 r
= GetHandleInformation(out
, &info
);
2321 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2322 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2324 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, HANDLE_FLAG_PROTECT_FROM_CLOSE
);
2325 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2326 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2327 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2328 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2329 ok(f
!= out
, "f == out\n");
2330 r
= GetHandleInformation(out
, &info
);
2331 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2332 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2333 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, 0);
2334 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2336 /* Test if DuplicateHandle allocates first free handle */
2347 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2348 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2349 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2350 ok(f
== out
, "f != out\n");
2352 DeleteFileA(file_name
);
2354 f
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2357 skip("DuplicateHandle on console handle\n");
2362 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2363 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2364 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2365 todo_wine
ok(f
!= out
, "f == out\n");
2369 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2370 static void _test_completion(int line
, HANDLE port
, DWORD ekey
, ULONG_PTR evalue
, ULONG_PTR eoverlapped
, DWORD wait
)
2372 LPOVERLAPPED overlapped
;
2377 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, wait
);
2379 ok_(__FILE__
, line
)(ret
, "GetQueuedCompletionStatus: %x\n", GetLastError());
2382 ok_(__FILE__
, line
)(key
== ekey
, "unexpected key %x\n", key
);
2383 ok_(__FILE__
, line
)(value
== evalue
, "unexpected value %p\n", (void *)value
);
2384 ok_(__FILE__
, line
)(overlapped
== (LPOVERLAPPED
)eoverlapped
, "unexpected overlapped %p\n", overlapped
);
2388 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2389 static void _create_process(int line
, const char *command
, LPPROCESS_INFORMATION pi
)
2392 char buffer
[MAX_PATH
];
2393 STARTUPINFOA si
= {0};
2395 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, command
);
2397 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, pi
);
2398 ok_(__FILE__
, line
)(ret
, "CreateProcess error %u\n", GetLastError());
2401 #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
2402 static void _test_assigned_proc(int line
, HANDLE job
, int expected_count
, ...)
2404 char buf
[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST
) + sizeof(ULONG_PTR
) * 20];
2405 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2411 memset(buf
, 0, sizeof(buf
));
2412 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2413 ok_(__FILE__
, line
)(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2416 todo_wine_if(expected_count
)
2417 ok_(__FILE__
, line
)(expected_count
== pid_list
->NumberOfAssignedProcesses
,
2418 "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n",
2419 expected_count
, pid_list
->NumberOfAssignedProcesses
);
2420 todo_wine_if(expected_count
)
2421 ok_(__FILE__
, line
)(expected_count
== pid_list
->NumberOfProcessIdsInList
,
2422 "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n",
2423 expected_count
, pid_list
->NumberOfProcessIdsInList
);
2425 va_start(valist
, expected_count
);
2426 for (n
= 0; n
< min(expected_count
, pid_list
->NumberOfProcessIdsInList
); ++n
)
2428 pid
= va_arg(valist
, DWORD
);
2429 ok_(__FILE__
, line
)(pid
== pid_list
->ProcessIdList
[n
],
2430 "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n",
2431 n
, pid
, pid_list
->ProcessIdList
[n
]);
2437 #define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc)
2438 static void _test_accounting(int line
, HANDLE job
, int total_proc
, int active_proc
, int terminated_proc
)
2440 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting
;
2444 memset(&basic_accounting
, 0, sizeof(basic_accounting
));
2445 ret
= pQueryInformationJobObject(job
, JobObjectBasicAccountingInformation
, &basic_accounting
, sizeof(basic_accounting
), &ret_len
);
2446 ok_(__FILE__
, line
)(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2449 /* Not going to check process times or page faults */
2451 todo_wine_if(total_proc
)
2452 ok_(__FILE__
, line
)(total_proc
== basic_accounting
.TotalProcesses
,
2453 "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n",
2454 total_proc
, basic_accounting
.TotalProcesses
);
2455 todo_wine_if(active_proc
)
2456 ok_(__FILE__
, line
)(active_proc
== basic_accounting
.ActiveProcesses
,
2457 "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n",
2458 active_proc
, basic_accounting
.ActiveProcesses
);
2459 ok_(__FILE__
, line
)(terminated_proc
== basic_accounting
.TotalTerminatedProcesses
,
2460 "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n",
2461 terminated_proc
, basic_accounting
.TotalTerminatedProcesses
);
2465 static void test_IsProcessInJob(void)
2468 PROCESS_INFORMATION pi
;
2472 if (!pIsProcessInJob
)
2474 win_skip("IsProcessInJob not available.\n");
2478 job
= pCreateJobObjectW(NULL
, NULL
);
2479 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2481 job2
= pCreateJobObjectW(NULL
, NULL
);
2482 ok(job2
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2484 create_process("wait", &pi
);
2487 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2488 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2489 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2490 test_assigned_proc(job
, 0);
2491 test_accounting(job
, 0, 0, 0);
2494 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2495 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2496 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2497 test_assigned_proc(job2
, 0);
2498 test_accounting(job2
, 0, 0, 0);
2501 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2502 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2503 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2505 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2506 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2509 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2510 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2511 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2512 test_assigned_proc(job
, 1, pi
.dwProcessId
);
2513 test_accounting(job
, 1, 1, 0);
2516 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2517 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2518 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2519 test_assigned_proc(job2
, 0);
2520 test_accounting(job2
, 0, 0, 0);
2523 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2524 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2525 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2527 TerminateProcess(pi
.hProcess
, 0);
2529 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2530 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2533 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2534 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2535 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2536 test_assigned_proc(job
, 0);
2537 test_accounting(job
, 1, 0, 0);
2539 CloseHandle(pi
.hProcess
);
2540 CloseHandle(pi
.hThread
);
2545 static void test_TerminateJobObject(void)
2548 PROCESS_INFORMATION pi
;
2552 job
= pCreateJobObjectW(NULL
, NULL
);
2553 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2554 test_assigned_proc(job
, 0);
2555 test_accounting(job
, 0, 0, 0);
2557 create_process("wait", &pi
);
2559 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2560 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2561 test_assigned_proc(job
, 1, pi
.dwProcessId
);
2562 test_accounting(job
, 1, 1, 0);
2564 ret
= pTerminateJobObject(job
, 123);
2565 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2567 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2568 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2569 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2570 test_assigned_proc(job
, 0);
2571 test_accounting(job
, 1, 0, 0);
2573 ret
= GetExitCodeProcess(pi
.hProcess
, &dwret
);
2574 ok(ret
, "GetExitCodeProcess error %u\n", GetLastError());
2575 ok(dwret
== 123 || broken(dwret
== 0) /* randomly fails on Win 2000 / XP */,
2576 "wrong exitcode %u\n", dwret
);
2578 CloseHandle(pi
.hProcess
);
2579 CloseHandle(pi
.hThread
);
2581 /* Test adding an already terminated process to a job object */
2582 create_process("exit", &pi
);
2584 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2585 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2587 SetLastError(0xdeadbeef);
2588 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2589 ok(!ret
, "AssignProcessToJobObject unexpectedly succeeded\n");
2590 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2591 test_assigned_proc(job
, 0);
2592 test_accounting(job
, 1, 0, 0);
2594 CloseHandle(pi
.hProcess
);
2595 CloseHandle(pi
.hThread
);
2600 static void test_QueryInformationJobObject(void)
2602 char buf
[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST
) + sizeof(ULONG_PTR
) * 4];
2603 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2604 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info
;
2605 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit_info
= &ext_limit_info
.BasicLimitInformation
;
2606 DWORD dwret
, ret_len
;
2607 PROCESS_INFORMATION pi
[2];
2611 job
= pCreateJobObjectW(NULL
, NULL
);
2612 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2614 /* Only active processes are returned */
2615 create_process("exit", &pi
[0]);
2616 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2617 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2618 dwret
= WaitForSingleObject(pi
[0].hProcess
, 1000);
2619 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2621 CloseHandle(pi
[0].hProcess
);
2622 CloseHandle(pi
[0].hThread
);
2624 create_process("wait", &pi
[0]);
2625 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2626 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2628 create_process("wait", &pi
[1]);
2629 ret
= pAssignProcessToJobObject(job
, pi
[1].hProcess
);
2630 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2632 SetLastError(0xdeadbeef);
2633 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2634 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
), &ret_len
);
2635 ok(!ret
, "QueryInformationJobObject expected failure\n");
2636 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2638 SetLastError(0xdeadbeef);
2639 memset(buf
, 0, sizeof(buf
));
2640 pid_list
->NumberOfAssignedProcesses
= 42;
2641 pid_list
->NumberOfProcessIdsInList
= 42;
2642 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2643 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[1]), &ret_len
);
2645 ok(!ret
, "QueryInformationJobObject expected failure\n");
2647 expect_eq_d(ERROR_MORE_DATA
, GetLastError());
2651 expect_eq_d(42, pid_list
->NumberOfAssignedProcesses
);
2653 expect_eq_d(42, pid_list
->NumberOfProcessIdsInList
);
2656 memset(buf
, 0, sizeof(buf
));
2657 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2658 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2661 if (pid_list
->NumberOfAssignedProcesses
== 3) /* Win 8 */
2662 win_skip("Number of assigned processes broken on Win 8\n");
2665 ULONG_PTR
*list
= pid_list
->ProcessIdList
;
2668 ok(ret_len
== FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[2]),
2669 "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2672 expect_eq_d(2, pid_list
->NumberOfAssignedProcesses
);
2674 expect_eq_d(2, pid_list
->NumberOfProcessIdsInList
);
2676 expect_eq_d(pi
[0].dwProcessId
, list
[0]);
2678 expect_eq_d(pi
[1].dwProcessId
, list
[1]);
2682 /* test JobObjectBasicLimitInformation */
2683 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2684 sizeof(*basic_limit_info
) - 1, &ret_len
);
2685 ok(!ret
, "QueryInformationJobObject expected failure\n");
2686 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2688 ret_len
= 0xdeadbeef;
2689 memset(basic_limit_info
, 0x11, sizeof(*basic_limit_info
));
2690 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2691 sizeof(*basic_limit_info
), &ret_len
);
2692 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2693 ok(ret_len
== sizeof(*basic_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2694 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2696 /* test JobObjectExtendedLimitInformation */
2697 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2698 sizeof(ext_limit_info
) - 1, &ret_len
);
2699 ok(!ret
, "QueryInformationJobObject expected failure\n");
2700 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2702 ret_len
= 0xdeadbeef;
2703 memset(&ext_limit_info
, 0x11, sizeof(ext_limit_info
));
2704 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2705 sizeof(ext_limit_info
), &ret_len
);
2706 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2707 ok(ret_len
== sizeof(ext_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2708 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2710 TerminateProcess(pi
[0].hProcess
, 0);
2711 CloseHandle(pi
[0].hProcess
);
2712 CloseHandle(pi
[0].hThread
);
2714 TerminateProcess(pi
[1].hProcess
, 0);
2715 CloseHandle(pi
[1].hProcess
);
2716 CloseHandle(pi
[1].hThread
);
2721 static void test_CompletionPort(void)
2723 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
2724 PROCESS_INFORMATION pi
;
2729 job
= pCreateJobObjectW(NULL
, NULL
);
2730 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2732 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
2733 ok(port
!= NULL
, "CreateIoCompletionPort error %u\n", GetLastError());
2735 port_info
.CompletionKey
= job
;
2736 port_info
.CompletionPort
= port
;
2737 ret
= pSetInformationJobObject(job
, JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
2738 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2740 create_process("wait", &pi
);
2742 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2743 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2745 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2747 TerminateProcess(pi
.hProcess
, 0);
2748 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2749 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2751 test_completion(port
, JOB_OBJECT_MSG_EXIT_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2752 test_completion(port
, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
, (DWORD_PTR
)job
, 0, 100);
2754 CloseHandle(pi
.hProcess
);
2755 CloseHandle(pi
.hThread
);
2760 static void test_KillOnJobClose(void)
2762 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2763 PROCESS_INFORMATION pi
;
2768 job
= pCreateJobObjectW(NULL
, NULL
);
2769 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2771 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
;
2772 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2773 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
2775 win_skip("Kill on job close limit not available\n");
2778 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2779 test_assigned_proc(job
, 0);
2780 test_accounting(job
, 0, 0, 0);
2782 create_process("wait", &pi
);
2784 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2785 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2786 test_assigned_proc(job
, 1, pi
.dwProcessId
);
2787 test_accounting(job
, 1, 1, 0);
2791 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2792 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2793 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2795 CloseHandle(pi
.hProcess
);
2796 CloseHandle(pi
.hThread
);
2799 static void test_WaitForJobObject(void)
2802 PROCESS_INFORMATION pi
;
2806 /* test waiting for a job object when the process is killed */
2807 job
= pCreateJobObjectW(NULL
, NULL
);
2808 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2810 dwret
= WaitForSingleObject(job
, 100);
2811 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2813 create_process("wait", &pi
);
2815 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2816 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2818 dwret
= WaitForSingleObject(job
, 100);
2819 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2821 ret
= pTerminateJobObject(job
, 123);
2822 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2824 dwret
= WaitForSingleObject(job
, 500);
2825 ok(dwret
== WAIT_OBJECT_0
|| broken(dwret
== WAIT_TIMEOUT
),
2826 "WaitForSingleObject returned %u\n", dwret
);
2828 if (dwret
== WAIT_TIMEOUT
) /* Win 2000/XP */
2833 ok(0, "HACK: Killing process to speed up the test\n");
2834 TerminateProcess(pi
.hProcess
, 0);
2837 CloseHandle(pi
.hProcess
);
2838 CloseHandle(pi
.hThread
);
2840 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2844 /* the object is not reset immediately */
2845 dwret
= WaitForSingleObject(job
, 100);
2846 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2848 CloseHandle(pi
.hProcess
);
2849 CloseHandle(pi
.hThread
);
2851 /* creating a new process doesn't reset the signalled state */
2852 create_process("wait", &pi
);
2854 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2855 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2857 dwret
= WaitForSingleObject(job
, 100);
2858 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2860 ret
= pTerminateJobObject(job
, 123);
2861 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2863 CloseHandle(pi
.hProcess
);
2864 CloseHandle(pi
.hThread
);
2868 /* repeat the test, but this time the process terminates properly */
2869 job
= pCreateJobObjectW(NULL
, NULL
);
2870 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2872 dwret
= WaitForSingleObject(job
, 100);
2873 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2875 create_process("exit", &pi
);
2877 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2878 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2880 dwret
= WaitForSingleObject(job
, 100);
2881 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2883 CloseHandle(pi
.hProcess
);
2884 CloseHandle(pi
.hThread
);
2888 static HANDLE
test_AddSelfToJob(void)
2893 job
= pCreateJobObjectW(NULL
, NULL
);
2894 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2896 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
2897 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2898 test_assigned_proc(job
, 1, GetCurrentProcessId());
2899 test_accounting(job
, 1, 1, 0);
2904 static void test_jobInheritance(HANDLE job
)
2906 char buffer
[MAX_PATH
];
2907 PROCESS_INFORMATION pi
;
2908 STARTUPINFOA si
= {0};
2912 if (!pIsProcessInJob
)
2914 win_skip("IsProcessInJob not available.\n");
2918 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2920 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2921 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2924 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2925 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2926 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2927 test_assigned_proc(job
, 2, GetCurrentProcessId(), pi
.dwProcessId
);
2928 test_accounting(job
, 2, 2, 0);
2930 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2931 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2933 CloseHandle(pi
.hProcess
);
2934 CloseHandle(pi
.hThread
);
2937 static void test_BreakawayOk(HANDLE job
)
2939 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2940 PROCESS_INFORMATION pi
;
2941 STARTUPINFOA si
= {0};
2942 char buffer
[MAX_PATH
];
2946 if (!pIsProcessInJob
)
2948 win_skip("IsProcessInJob not available.\n");
2952 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2954 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2955 ok(!ret
, "CreateProcessA expected failure\n");
2956 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2957 test_assigned_proc(job
, 1, GetCurrentProcessId());
2958 test_accounting(job
, 2, 1, 0);
2962 TerminateProcess(pi
.hProcess
, 0);
2964 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2965 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2967 CloseHandle(pi
.hProcess
);
2968 CloseHandle(pi
.hThread
);
2971 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
2972 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2973 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2975 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2976 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2978 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2979 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2980 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2981 test_assigned_proc(job
, 1, GetCurrentProcessId());
2982 test_accounting(job
, 2, 1, 0);
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
);
2990 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
2991 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2992 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2994 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2995 ok(ret
, "CreateProcess error %u\n", GetLastError());
2997 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2998 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2999 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
3000 test_assigned_proc(job
, 1, GetCurrentProcessId());
3001 test_accounting(job
, 2, 1, 0);
3003 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
3004 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
3006 CloseHandle(pi
.hProcess
);
3007 CloseHandle(pi
.hThread
);
3009 /* unset breakaway ok */
3010 limit_info
.BasicLimitInformation
.LimitFlags
= 0;
3011 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
3012 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
3015 static void test_StartupNoConsole(void)
3018 char buffer
[MAX_PATH
];
3019 STARTUPINFOA startup
;
3020 PROCESS_INFORMATION info
;
3022 memset(&startup
, 0, sizeof(startup
));
3023 startup
.cb
= sizeof(startup
);
3024 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3025 startup
.wShowWindow
= SW_SHOWNORMAL
;
3026 get_file_name(resfile
);
3027 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
3028 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
3029 &info
), "CreateProcess\n");
3030 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
3031 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
3032 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
3033 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
3034 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
3035 okChildInt("TEB", "hStdInput", 0);
3036 okChildInt("TEB", "hStdOutput", 0);
3037 okChildInt("TEB", "hStdError", 0);
3039 DeleteFileA(resfile
);
3043 static void test_DetachConsoleHandles(void)
3046 char buffer
[MAX_PATH
];
3047 STARTUPINFOA startup
;
3048 PROCESS_INFORMATION info
;
3051 memset(&startup
, 0, sizeof(startup
));
3052 startup
.cb
= sizeof(startup
);
3053 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
3054 startup
.wShowWindow
= SW_SHOWNORMAL
;
3055 startup
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
3056 startup
.hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
3057 startup
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
3058 get_file_name(resfile
);
3059 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
3060 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
3061 &info
), "CreateProcess\n");
3062 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
3063 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
3065 result
= GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile
);
3066 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3067 result
= GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile
);
3068 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3069 result
= GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile
);
3070 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3071 result
= GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile
);
3072 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3073 result
= GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile
);
3074 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3075 result
= GetPrivateProfileIntA("TEB", "hStdError", 0, resfile
);
3076 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
3079 DeleteFileA(resfile
);
3083 #if defined(__i386__) || defined(__x86_64__)
3084 static BOOL
read_nt_header(HANDLE process_handle
, MEMORY_BASIC_INFORMATION
*mbi
,
3085 IMAGE_NT_HEADERS
*nt_header
)
3087 IMAGE_DOS_HEADER dos_header
;
3089 if (!ReadProcessMemory(process_handle
, mbi
->BaseAddress
, &dos_header
, sizeof(dos_header
), NULL
))
3092 if ((dos_header
.e_magic
!= IMAGE_DOS_SIGNATURE
) ||
3093 ((ULONG
)dos_header
.e_lfanew
> mbi
->RegionSize
) ||
3094 (dos_header
.e_lfanew
< sizeof(dos_header
)))
3097 if (!ReadProcessMemory(process_handle
, (char *)mbi
->BaseAddress
+ dos_header
.e_lfanew
,
3098 nt_header
, sizeof(*nt_header
), NULL
))
3101 return (nt_header
->Signature
== IMAGE_NT_SIGNATURE
);
3104 static PVOID
get_process_exe(HANDLE process_handle
, IMAGE_NT_HEADERS
*nt_header
)
3106 PVOID exe_base
, address
;
3107 MEMORY_BASIC_INFORMATION mbi
;
3109 /* Find the EXE base in the new process */
3111 for (address
= NULL
;
3112 VirtualQueryEx(process_handle
, address
, &mbi
, sizeof(mbi
)) ;
3113 address
= (char *)mbi
.BaseAddress
+ mbi
.RegionSize
) {
3114 if ((mbi
.Type
== SEC_IMAGE
) &&
3115 read_nt_header(process_handle
, &mbi
, nt_header
) &&
3116 !(nt_header
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)) {
3117 exe_base
= mbi
.BaseAddress
;
3125 static BOOL
are_imports_resolved(HANDLE process_handle
, PVOID module_base
, IMAGE_NT_HEADERS
*nt_header
)
3128 IMAGE_IMPORT_DESCRIPTOR iid
;
3129 ULONG_PTR orig_iat_entry_value
, iat_entry_value
;
3131 ok(nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
, "Import table VA is zero\n");
3132 ok(nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].Size
, "Import table Size is zero\n");
3134 if (!nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
||
3135 !nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].Size
)
3138 /* Read the first IID */
3139 ret
= ReadProcessMemory(process_handle
,
3140 (char *)module_base
+ nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
].VirtualAddress
,
3141 &iid
, sizeof(iid
), NULL
);
3142 ok(ret
, "Failed to read remote module IID (%d)\n", GetLastError());
3144 /* Validate the IID is present and not a bound import, and that we have
3145 an OriginalFirstThunk to compare with */
3146 ok(iid
.Name
, "Module first IID does not have a Name\n");
3147 ok(iid
.FirstThunk
, "Module first IID does not have a FirstThunk\n");
3148 ok(!iid
.TimeDateStamp
, "Module first IID is a bound import (UNSUPPORTED for current test)\n");
3149 ok(iid
.OriginalFirstThunk
, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3151 /* Read a single IAT entry from the FirstThunk */
3152 ret
= ReadProcessMemory(process_handle
, (char *)module_base
+ iid
.FirstThunk
,
3153 &iat_entry_value
, sizeof(iat_entry_value
), NULL
);
3154 ok(ret
, "Failed to read IAT entry from FirstThunk (%d)\n", GetLastError());
3155 ok(iat_entry_value
, "IAT entry in FirstThunk is NULL\n");
3157 /* Read a single IAT entry from the OriginalFirstThunk */
3158 ret
= ReadProcessMemory(process_handle
, (char *)module_base
+ iid
.OriginalFirstThunk
,
3159 &orig_iat_entry_value
, sizeof(orig_iat_entry_value
), NULL
);
3160 ok(ret
, "Failed to read IAT entry from OriginalFirstThunk (%d)\n", GetLastError());
3161 ok(orig_iat_entry_value
, "IAT entry in OriginalFirstThunk is NULL\n");
3163 return iat_entry_value
!= orig_iat_entry_value
;
3166 static void test_SuspendProcessNewThread(void)
3169 STARTUPINFOA si
= {0};
3170 PROCESS_INFORMATION pi
= {0};
3171 PVOID exe_base
, exit_thread_ptr
;
3172 IMAGE_NT_HEADERS nt_header
;
3173 HANDLE thread_handle
= NULL
;
3174 DWORD dret
, exit_code
= 0;
3177 exit_thread_ptr
= GetProcAddress(hkernel32
, "ExitThread");
3178 ok(exit_thread_ptr
!= NULL
, "GetProcAddress ExitThread failed\n");
3181 ret
= CreateProcessA(NULL
, selfname
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
3182 ok(ret
, "Failed to create process (%d)\n", GetLastError());
3184 exe_base
= get_process_exe(pi
.hProcess
, &nt_header
);
3185 ok(exe_base
!= NULL
, "Could not find EXE in remote process\n");
3187 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3188 ok(!ret
, "IAT entry resolved prematurely\n");
3190 thread_handle
= CreateRemoteThread(pi
.hProcess
, NULL
, 0,
3191 (LPTHREAD_START_ROUTINE
)exit_thread_ptr
,
3192 (PVOID
)(ULONG_PTR
)0x1234, CREATE_SUSPENDED
, NULL
);
3193 ok(thread_handle
!= NULL
, "Could not create remote thread (%d)\n", GetLastError());
3195 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3196 ok(!ret
, "IAT entry resolved prematurely\n");
3198 ctx
.ContextFlags
= CONTEXT_ALL
;
3199 ret
= GetThreadContext( thread_handle
, &ctx
);
3200 ok( ret
, "Failed retrieving remote thread context (%d)\n", GetLastError() );
3201 ok( ctx
.ContextFlags
== CONTEXT_ALL
, "wrong flags %x\n", ctx
.ContextFlags
);
3203 ok( !ctx
.Rax
, "rax is not zero %lx\n", ctx
.Rax
);
3204 ok( !ctx
.Rbx
, "rbx is not zero %lx\n", ctx
.Rbx
);
3205 ok( ctx
.Rcx
== (ULONG_PTR
)exit_thread_ptr
, "wrong rcx %lx/%p\n", ctx
.Rcx
, exit_thread_ptr
);
3206 ok( ctx
.Rdx
== 0x1234, "wrong rdx %lx\n", ctx
.Rdx
);
3207 ok( !ctx
.Rsi
, "rsi is not zero %lx\n", ctx
.Rsi
);
3208 ok( !ctx
.Rdi
, "rdi is not zero %lx\n", ctx
.Rdi
);
3209 ok( !ctx
.Rbp
, "rbp is not zero %lx\n", ctx
.Rbp
);
3210 ok( !ctx
.R8
, "r8 is not zero %lx\n", ctx
.R8
);
3211 ok( !ctx
.R9
, "r9 is not zero %lx\n", ctx
.R9
);
3212 ok( !ctx
.R10
, "r10 is not zero %lx\n", ctx
.R10
);
3213 ok( !ctx
.R11
, "r11 is not zero %lx\n", ctx
.R11
);
3214 ok( !ctx
.R12
, "r12 is not zero %lx\n", ctx
.R12
);
3215 ok( !ctx
.R13
, "r13 is not zero %lx\n", ctx
.R13
);
3216 ok( !ctx
.R14
, "r14 is not zero %lx\n", ctx
.R14
);
3217 ok( !ctx
.R15
, "r15 is not zero %lx\n", ctx
.R15
);
3218 ok( !((ctx
.Rsp
+ 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx
.Rsp
);
3219 ok( ctx
.EFlags
== 0x200, "wrong flags %08x\n", ctx
.EFlags
);
3220 ok( ctx
.MxCsr
== 0x1f80, "wrong mxcsr %08x\n", ctx
.MxCsr
);
3221 ok( ctx
.FltSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FltSave
.ControlWord
);
3223 ok( !ctx
.Ebp
|| broken(ctx
.Ebp
), /* winxp */ "ebp is not zero %08x\n", ctx
.Ebp
);
3224 if (!ctx
.Ebp
) /* winxp is completely different */
3226 ok( !ctx
.Ecx
, "ecx is not zero %08x\n", ctx
.Ecx
);
3227 ok( !ctx
.Edx
, "edx is not zero %08x\n", ctx
.Edx
);
3228 ok( !ctx
.Esi
, "esi is not zero %08x\n", ctx
.Esi
);
3229 ok( !ctx
.Edi
, "edi is not zero %08x\n", ctx
.Edi
);
3231 ok( ctx
.Eax
== (ULONG_PTR
)exit_thread_ptr
, "wrong eax %08x/%p\n", ctx
.Eax
, exit_thread_ptr
);
3232 ok( ctx
.Ebx
== 0x1234, "wrong ebx %08x\n", ctx
.Ebx
);
3233 ok( !((ctx
.Esp
+ 0x10) & 0xfff) || broken( !((ctx
.Esp
+ 4) & 0xfff) ), /* winxp, w2k3 */
3234 "esp is not at top of stack page or properly aligned: %08x\n", ctx
.Esp
);
3235 ok( (ctx
.EFlags
& ~2) == 0x200, "wrong flags %08x\n", ctx
.EFlags
);
3236 ok( (WORD
)ctx
.FloatSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FloatSave
.ControlWord
);
3237 ok( *(WORD
*)ctx
.ExtendedRegisters
== 0x27f, "wrong control %08x\n", *(WORD
*)ctx
.ExtendedRegisters
);
3240 ResumeThread( thread_handle
);
3241 dret
= WaitForSingleObject(thread_handle
, 60000);
3242 ok(dret
== WAIT_OBJECT_0
, "Waiting for remote thread failed (%d)\n", GetLastError());
3243 ret
= GetExitCodeThread(thread_handle
, &exit_code
);
3244 ok(ret
, "Failed to retrieve remote thread exit code (%d)\n", GetLastError());
3245 ok(exit_code
== 0x1234, "Invalid remote thread exit code\n");
3247 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3248 ok(ret
, "EXE IAT entry not resolved\n");
3251 CloseHandle(thread_handle
);
3253 TerminateProcess(pi
.hProcess
, 0);
3254 WaitForSingleObject(pi
.hProcess
, 10000);
3255 CloseHandle(pi
.hProcess
);
3256 CloseHandle(pi
.hThread
);
3259 static void test_SuspendProcessState(void)
3263 ULONG pipe_write_buf
;
3264 ULONG pipe_read_buf
;
3265 ULONG bytes_returned
;
3266 CHAR pipe_name
[MAX_PATH
];
3270 struct remote_rop_chain
3272 void *exit_process_ptr
;
3277 ULONG_PTR pipe_read_buf_size
;
3278 ULONG_PTR bytes_returned
;
3282 struct remote_rop_chain
3284 void *exit_process_ptr
;
3285 ULONG_PTR pipe_name
;
3286 ULONG_PTR pipe_write_buf
;
3287 ULONG_PTR pipe_write_buf_size
;
3288 ULONG_PTR pipe_read_buf
;
3289 ULONG_PTR pipe_read_buf_size
;
3290 ULONG_PTR bytes_returned
;
3292 void *unreached_ret
;
3293 ULONG_PTR exit_code
;
3297 static const char pipe_name
[] = "\\\\.\\pipe\\TestPipe";
3298 static const ULONG pipe_write_magic
= 0x454e4957;
3299 STARTUPINFOA si
= {0};
3300 PROCESS_INFORMATION pi
= {0};
3301 PVOID exe_base
, remote_pipe_params
, exit_process_ptr
,
3303 IMAGE_NT_HEADERS nt_header
;
3304 struct pipe_params pipe_params
;
3305 struct remote_rop_chain rop_chain
;
3307 HANDLE server_pipe_handle
;
3308 BOOL pipe_connected
;
3309 ULONG pipe_magic
, numb
;
3311 void *entry_ptr
, *peb_ptr
;
3314 exit_process_ptr
= GetProcAddress(hkernel32
, "ExitProcess");
3315 ok(exit_process_ptr
!= NULL
, "GetProcAddress ExitProcess failed\n");
3317 call_named_pipe_a
= GetProcAddress(hkernel32
, "CallNamedPipeA");
3318 ok(call_named_pipe_a
!= NULL
, "GetProcAddress CallNamedPipeA failed\n");
3321 ret
= CreateProcessA(NULL
, selfname
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
3322 ok(ret
, "Failed to create process (%d)\n", GetLastError());
3324 exe_base
= get_process_exe(pi
.hProcess
, &nt_header
);
3325 /* Make sure we found the EXE in the new process */
3326 ok(exe_base
!= NULL
, "Could not find EXE in remote process\n");
3328 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3329 ok(!ret
, "IAT entry resolved prematurely\n");
3331 server_pipe_handle
= CreateNamedPipeA(pipe_name
, PIPE_ACCESS_DUPLEX
| FILE_FLAG_WRITE_THROUGH
,
3332 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
, 1, 0x20000, 0x20000,
3334 ok(server_pipe_handle
!= INVALID_HANDLE_VALUE
, "Failed to create communication pipe (%d)\n", GetLastError());
3336 /* Set up the remote process environment */
3337 ctx
.ContextFlags
= CONTEXT_ALL
;
3338 ret
= GetThreadContext(pi
.hThread
, &ctx
);
3339 ok(ret
, "Failed retrieving remote thread context (%d)\n", GetLastError());
3340 ok( ctx
.ContextFlags
== CONTEXT_ALL
, "wrong flags %x\n", ctx
.ContextFlags
);
3342 remote_pipe_params
= VirtualAllocEx(pi
.hProcess
, NULL
, sizeof(pipe_params
), MEM_COMMIT
, PAGE_READWRITE
);
3343 ok(remote_pipe_params
!= NULL
, "Failed allocating memory in remote process (%d)\n", GetLastError());
3345 pipe_params
.pipe_write_buf
= pipe_write_magic
;
3346 pipe_params
.pipe_read_buf
= 0;
3347 pipe_params
.bytes_returned
= 0;
3348 strcpy(pipe_params
.pipe_name
, pipe_name
);
3350 ret
= WriteProcessMemory(pi
.hProcess
, remote_pipe_params
,
3351 &pipe_params
, sizeof(pipe_params
), NULL
);
3352 ok(ret
, "Failed to write to remote process memory (%d)\n", GetLastError());
3355 ok( !ctx
.Rax
, "rax is not zero %lx\n", ctx
.Rax
);
3356 ok( !ctx
.Rbx
, "rbx is not zero %lx\n", ctx
.Rbx
);
3357 ok( !ctx
.Rsi
, "rsi is not zero %lx\n", ctx
.Rsi
);
3358 ok( !ctx
.Rdi
, "rdi is not zero %lx\n", ctx
.Rdi
);
3359 ok( !ctx
.Rbp
, "rbp is not zero %lx\n", ctx
.Rbp
);
3360 ok( !ctx
.R8
, "r8 is not zero %lx\n", ctx
.R8
);
3361 ok( !ctx
.R9
, "r9 is not zero %lx\n", ctx
.R9
);
3362 ok( !ctx
.R10
, "r10 is not zero %lx\n", ctx
.R10
);
3363 ok( !ctx
.R11
, "r11 is not zero %lx\n", ctx
.R11
);
3364 ok( !ctx
.R12
, "r12 is not zero %lx\n", ctx
.R12
);
3365 ok( !ctx
.R13
, "r13 is not zero %lx\n", ctx
.R13
);
3366 ok( !ctx
.R14
, "r14 is not zero %lx\n", ctx
.R14
);
3367 ok( !ctx
.R15
, "r15 is not zero %lx\n", ctx
.R15
);
3368 ok( !((ctx
.Rsp
+ 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx
.Rsp
);
3369 ok( ctx
.EFlags
== 0x200, "wrong flags %08x\n", ctx
.EFlags
);
3370 ok( ctx
.MxCsr
== 0x1f80, "wrong mxcsr %08x\n", ctx
.MxCsr
);
3371 ok( ctx
.FltSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FltSave
.ControlWord
);
3372 entry_ptr
= (void *)ctx
.Rcx
;
3373 peb_ptr
= (void *)ctx
.Rdx
;
3375 rop_chain
.exit_process_ptr
= exit_process_ptr
;
3376 ctx
.Rcx
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_name
);
3377 ctx
.Rdx
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_write_buf
);
3378 ctx
.R8
= sizeof(pipe_params
.pipe_write_buf
);
3379 ctx
.R9
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_read_buf
);
3380 rop_chain
.pipe_read_buf_size
= sizeof(pipe_params
.pipe_read_buf
);
3381 rop_chain
.bytes_returned
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, bytes_returned
);
3382 rop_chain
.timeout
= 10000;
3384 ctx
.Rip
= (ULONG_PTR
)call_named_pipe_a
;
3385 ctx
.Rsp
-= sizeof(rop_chain
);
3386 ret
= WriteProcessMemory(pi
.hProcess
, (void *)ctx
.Rsp
, &rop_chain
, sizeof(rop_chain
), NULL
);
3387 ok(ret
, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3389 ok( !ctx
.Ebp
|| broken(ctx
.Ebp
), /* winxp */ "ebp is not zero %08x\n", ctx
.Ebp
);
3390 if (!ctx
.Ebp
) /* winxp is completely different */
3392 ok( !ctx
.Ecx
, "ecx is not zero %08x\n", ctx
.Ecx
);
3393 ok( !ctx
.Edx
, "edx is not zero %08x\n", ctx
.Edx
);
3394 ok( !ctx
.Esi
, "esi is not zero %08x\n", ctx
.Esi
);
3395 ok( !ctx
.Edi
, "edi is not zero %08x\n", ctx
.Edi
);
3397 ok( !((ctx
.Esp
+ 0x10) & 0xfff) || broken( !((ctx
.Esp
+ 4) & 0xfff) ), /* winxp, w2k3 */
3398 "esp is not at top of stack page or properly aligned: %08x\n", ctx
.Esp
);
3399 ok( (ctx
.EFlags
& ~2) == 0x200, "wrong flags %08x\n", ctx
.EFlags
);
3400 ok( (WORD
)ctx
.FloatSave
.ControlWord
== 0x27f, "wrong control %08x\n", ctx
.FloatSave
.ControlWord
);
3401 ok( *(WORD
*)ctx
.ExtendedRegisters
== 0x27f, "wrong control %08x\n", *(WORD
*)ctx
.ExtendedRegisters
);
3402 entry_ptr
= (void *)ctx
.Eax
;
3403 peb_ptr
= (void *)ctx
.Ebx
;
3405 rop_chain
.exit_process_ptr
= exit_process_ptr
;
3406 rop_chain
.pipe_name
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_name
);
3407 rop_chain
.pipe_write_buf
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_write_buf
);
3408 rop_chain
.pipe_write_buf_size
= sizeof(pipe_params
.pipe_write_buf
);
3409 rop_chain
.pipe_read_buf
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, pipe_read_buf
);
3410 rop_chain
.pipe_read_buf_size
= sizeof(pipe_params
.pipe_read_buf
);
3411 rop_chain
.bytes_returned
= (ULONG_PTR
)remote_pipe_params
+ offsetof(struct pipe_params
, bytes_returned
);
3412 rop_chain
.timeout
= 10000;
3413 rop_chain
.exit_code
= 0;
3415 ctx
.Eip
= (ULONG_PTR
)call_named_pipe_a
;
3416 ctx
.Esp
-= sizeof(rop_chain
);
3417 ret
= WriteProcessMemory(pi
.hProcess
, (void *)ctx
.Esp
, &rop_chain
, sizeof(rop_chain
), NULL
);
3418 ok(ret
, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3421 ret
= ReadProcessMemory( pi
.hProcess
, peb_ptr
, &child_peb
, sizeof(child_peb
), NULL
);
3422 ok( ret
, "Failed to read PEB (%u)\n", GetLastError() );
3423 ok( child_peb
.ImageBaseAddress
== exe_base
, "wrong base %p/%p\n",
3424 child_peb
.ImageBaseAddress
, exe_base
);
3425 ok( entry_ptr
== (char *)exe_base
+ nt_header
.OptionalHeader
.AddressOfEntryPoint
,
3426 "wrong entry point %p/%p\n", entry_ptr
,
3427 (char *)exe_base
+ nt_header
.OptionalHeader
.AddressOfEntryPoint
);
3429 ret
= SetThreadContext(pi
.hThread
, &ctx
);
3430 ok(ret
, "Failed to set remote thread context (%d)\n", GetLastError());
3432 ResumeThread(pi
.hThread
);
3434 pipe_connected
= ConnectNamedPipe(server_pipe_handle
, NULL
) || (GetLastError() == ERROR_PIPE_CONNECTED
);
3435 ok(pipe_connected
, "Pipe did not connect\n");
3437 ret
= ReadFile(server_pipe_handle
, &pipe_magic
, sizeof(pipe_magic
), &numb
, NULL
);
3438 ok(ret
, "Failed to read buffer from pipe (%d)\n", GetLastError());
3440 ok(pipe_magic
== pipe_write_magic
, "Did not get the correct magic from the remote process\n");
3442 /* Validate the Imports, at this point the thread in the new process should have
3443 initialized the EXE module imports and call each dll DllMain notifying it on
3444 the new thread in the process. */
3445 ret
= are_imports_resolved(pi
.hProcess
, exe_base
, &nt_header
);
3446 ok(ret
, "EXE IAT is not resolved\n");
3448 ret
= WriteFile(server_pipe_handle
, &pipe_magic
, sizeof(pipe_magic
), &numb
, NULL
);
3449 ok(ret
, "Failed to write the magic back to the pipe (%d)\n", GetLastError());
3451 CloseHandle(server_pipe_handle
);
3452 TerminateProcess(pi
.hProcess
, 0);
3453 WaitForSingleObject(pi
.hProcess
, 10000);
3454 CloseHandle(pi
.hProcess
);
3455 CloseHandle(pi
.hThread
);
3458 static void test_SuspendProcessNewThread(void)
3461 static void test_SuspendProcessState(void)
3466 static void test_DetachStdHandles(void)
3469 char buffer
[MAX_PATH
], tempfile
[MAX_PATH
];
3470 STARTUPINFOA startup
;
3471 PROCESS_INFORMATION info
;
3472 HANDLE hstdin
, hstdout
, hstderr
, htemp
;
3475 hstdin
= GetStdHandle(STD_INPUT_HANDLE
);
3476 hstdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
3477 hstderr
= GetStdHandle(STD_ERROR_HANDLE
);
3479 get_file_name(tempfile
);
3480 htemp
= CreateFileA(tempfile
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
3481 ok(htemp
!= INVALID_HANDLE_VALUE
, "failed opening temporary file\n");
3483 memset(&startup
, 0, sizeof(startup
));
3484 startup
.cb
= sizeof(startup
);
3485 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3486 startup
.wShowWindow
= SW_SHOWNORMAL
;
3487 get_file_name(resfile
);
3488 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
3490 SetStdHandle(STD_INPUT_HANDLE
, htemp
);
3491 SetStdHandle(STD_OUTPUT_HANDLE
, htemp
);
3492 SetStdHandle(STD_ERROR_HANDLE
, htemp
);
3494 res
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
3497 SetStdHandle(STD_INPUT_HANDLE
, hstdin
);
3498 SetStdHandle(STD_OUTPUT_HANDLE
, hstdout
);
3499 SetStdHandle(STD_ERROR_HANDLE
, hstderr
);
3501 ok(res
, "CreateProcess failed\n");
3502 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
3503 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
3504 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
3505 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
3506 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
3507 okChildInt("TEB", "hStdInput", 0);
3508 okChildInt("TEB", "hStdOutput", 0);
3509 okChildInt("TEB", "hStdError", 0);
3511 DeleteFileA(resfile
);
3514 DeleteFileA(tempfile
);
3518 static void test_GetNumaProcessorNode(void)
3525 if (!pGetNumaProcessorNode
)
3527 win_skip("GetNumaProcessorNode is missing\n");
3532 for (i
= 0; i
< 256; i
++)
3534 SetLastError(0xdeadbeef);
3535 node
= (i
< si
.dwNumberOfProcessors
) ? 0xFF : 0xAA;
3536 ret
= pGetNumaProcessorNode(i
, &node
);
3537 if (i
< si
.dwNumberOfProcessors
)
3539 ok(ret
, "GetNumaProcessorNode returned FALSE for processor %d\n", i
);
3540 ok(node
!= 0xFF, "expected node != 0xFF, but got 0xFF\n");
3544 ok(!ret
, "GetNumaProcessorNode returned TRUE for processor %d\n", i
);
3545 ok(node
== 0xFF || broken(node
== 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node
);
3546 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3551 static void test_session_info(void)
3553 DWORD session_id
, active_session
;
3556 if (!pProcessIdToSessionId
)
3558 win_skip("ProcessIdToSessionId is missing\n");
3562 r
= pProcessIdToSessionId(GetCurrentProcessId(), &session_id
);
3563 ok(r
, "ProcessIdToSessionId failed: %u\n", GetLastError());
3564 trace("session_id = %x\n", session_id
);
3566 active_session
= pWTSGetActiveConsoleSessionId();
3567 trace("active_session = %x\n", active_session
);
3570 static void test_process_info(void)
3573 static const ULONG info_size
[] =
3575 sizeof(PROCESS_BASIC_INFORMATION
) /* ProcessBasicInformation */,
3576 sizeof(QUOTA_LIMITS
) /* ProcessQuotaLimits */,
3577 sizeof(IO_COUNTERS
) /* ProcessIoCounters */,
3578 sizeof(VM_COUNTERS
) /* ProcessVmCounters */,
3579 sizeof(KERNEL_USER_TIMES
) /* ProcessTimes */,
3580 sizeof(ULONG
) /* ProcessBasePriority */,
3581 sizeof(ULONG
) /* ProcessRaisePriority */,
3582 sizeof(HANDLE
) /* ProcessDebugPort */,
3583 sizeof(HANDLE
) /* ProcessExceptionPort */,
3584 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3585 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3586 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3587 sizeof(ULONG
) /* ProcessDefaultHardErrorMode */,
3588 0 /* ProcessIoPortHandlers: kernel-mode only */,
3589 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3590 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3591 sizeof(ULONG
) /* ProcessUserModeIOPL */,
3592 sizeof(BOOLEAN
) /* ProcessEnableAlignmentFaultFixup */,
3593 sizeof(PROCESS_PRIORITY_CLASS
) /* ProcessPriorityClass */,
3594 sizeof(ULONG
) /* ProcessWx86Information */,
3595 sizeof(ULONG
) /* ProcessHandleCount */,
3596 sizeof(ULONG_PTR
) /* ProcessAffinityMask */,
3597 sizeof(ULONG
) /* ProcessPriorityBoost */,
3598 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3599 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3600 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3601 sizeof(ULONG_PTR
) /* ProcessWow64Information */,
3602 sizeof(buf
) /* ProcessImageFileName */,
3603 sizeof(ULONG
) /* ProcessLUIDDeviceMapsEnabled */,
3604 sizeof(ULONG
) /* ProcessBreakOnTermination */,
3605 sizeof(HANDLE
) /* ProcessDebugObjectHandle */,
3606 sizeof(ULONG
) /* ProcessDebugFlags */,
3607 sizeof(buf
) /* ProcessHandleTracing */,
3608 sizeof(ULONG
) /* ProcessIoPriority */,
3609 sizeof(ULONG
) /* ProcessExecuteFlags */,
3610 0 /* FIXME: sizeof(?) ProcessTlsInformation */,
3611 0 /* FIXME: sizeof(?) ProcessCookie */,
3612 sizeof(SECTION_IMAGE_INFORMATION
) /* ProcessImageInformation */,
3613 0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */,
3614 sizeof(ULONG
) /* ProcessPagePriority */,
3615 40 /* ProcessInstrumentationCallback */,
3616 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
3617 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
3618 sizeof(buf
) /* ProcessImageFileNameWin32 */,
3619 sizeof(HANDLE
) /* ProcessImageFileMapping */,
3620 0 /* FIXME: sizeof(PROCESS_AFFINITY_UPDATE_MODE) ProcessAffinityUpdateMode */,
3621 0 /* FIXME: sizeof(PROCESS_MEMORY_ALLOCATION_MODE) ProcessMemoryAllocationMode */,
3622 sizeof(USHORT
) /* ProcessGroupInformation */,
3623 sizeof(ULONG
) /* ProcessTokenVirtualizationEnabled */,
3624 sizeof(ULONG_PTR
) /* ProcessConsoleHostProcess */,
3625 0 /* FIXME: sizeof(PROCESS_WINDOW_INFORMATION) ProcessWindowInformation */,
3626 #if 0 /* FIXME: Add remaining classes */
3627 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION
) /* ProcessHandleInformation */,
3628 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION
) /* ProcessMitigationPolicy */,
3629 sizeof(ProcessDynamicFunctionTableInformation
) /* ProcessDynamicFunctionTableInformation */,
3630 sizeof(?) /* ProcessHandleCheckingMode */,
3631 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION
) /* ProcessKeepAliveCount */,
3632 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION
) /* ProcessRevokeFileHandles */,
3633 sizeof(PROCESS_WORKING_SET_CONTROL
) /* ProcessWorkingSetControl */,
3634 sizeof(?) /* ProcessHandleTable */,
3635 sizeof(?) /* ProcessCheckStackExtentsMode */,
3636 sizeof(buf
) /* ProcessCommandLineInformation */,
3637 sizeof(PS_PROTECTION
) /* ProcessProtectionInformation */,
3638 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO
) /* ProcessMemoryExhaustion */,
3639 sizeof(PROCESS_FAULT_INFORMATION
) /* ProcessFaultInformation */,
3640 sizeof(PROCESS_TELEMETRY_ID_INFORMATION
) /* ProcessTelemetryIdInformation */,
3641 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION
) /* ProcessCommitReleaseInformation */,
3642 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3643 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3644 0 /* ProcessReserved1Information */,
3645 0 /* ProcessReserved2Information */,
3646 sizeof(?) /* ProcessSubsystemProcess */,
3647 sizeof(PROCESS_JOB_MEMORY_INFO
) /* ProcessJobMemoryInformation */,
3651 ULONG i
, status
, ret_len
, size
;
3653 if (!pNtQueryInformationProcess
)
3655 win_skip("NtQueryInformationProcess is not available on this platform\n");
3659 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
3662 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
3666 for (i
= 0; i
< MaxProcessInfoClass
; i
++)
3668 size
= info_size
[i
];
3669 if (!size
) size
= sizeof(buf
);
3671 status
= pNtQueryInformationProcess(hproc
, i
, buf
, info_size
[i
], &ret_len
);
3672 if (status
== STATUS_NOT_IMPLEMENTED
) continue;
3673 if (status
== STATUS_INVALID_INFO_CLASS
) continue;
3674 if (status
== STATUS_INFO_LENGTH_MISMATCH
) continue;
3678 case ProcessBasicInformation
:
3679 case ProcessQuotaLimits
:
3681 case ProcessPriorityClass
:
3682 case ProcessPriorityBoost
:
3683 case ProcessLUIDDeviceMapsEnabled
:
3684 case 33 /* ProcessIoPriority */:
3685 case ProcessIoCounters
:
3686 case ProcessVmCounters
:
3687 case ProcessWow64Information
:
3688 case ProcessDefaultHardErrorMode
:
3689 case ProcessHandleCount
:
3690 case ProcessImageFileName
:
3691 case ProcessImageInformation
:
3692 case ProcessPagePriority
:
3693 case ProcessImageFileNameWin32
:
3694 ok(status
== STATUS_SUCCESS
, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3697 case ProcessAffinityMask
:
3698 case ProcessBreakOnTermination
:
3699 case ProcessGroupInformation
:
3700 case ProcessConsoleHostProcess
:
3701 ok(status
== STATUS_ACCESS_DENIED
/* before win8 */ || status
== STATUS_SUCCESS
/* win8 is less strict */,
3702 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3705 case ProcessDebugObjectHandle
:
3706 ok(status
== STATUS_ACCESS_DENIED
|| status
== STATUS_PORT_NOT_SET
,
3707 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3710 case ProcessExecuteFlags
:
3711 case ProcessDebugPort
:
3712 case ProcessDebugFlags
:
3715 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3719 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3727 static void test_GetLogicalProcessorInformationEx(void)
3729 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*info
;
3733 if (!pGetLogicalProcessorInformationEx
)
3735 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3739 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, NULL
);
3740 ok(!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "got %d, error %d\n", ret
, GetLastError());
3743 ret
= pGetLogicalProcessorInformationEx(RelationProcessorCore
, NULL
, &len
);
3744 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %d\n", ret
, GetLastError());
3745 ok(len
> 0, "got %u\n", len
);
3748 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, &len
);
3749 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %d\n", ret
, GetLastError());
3750 ok(len
> 0, "got %u\n", len
);
3752 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
3753 ret
= pGetLogicalProcessorInformationEx(RelationAll
, info
, &len
);
3754 ok(ret
, "got %d, error %d\n", ret
, GetLastError());
3755 ok(info
->Size
> 0, "got %u\n", info
->Size
);
3756 HeapFree(GetProcessHeap(), 0, info
);
3759 static void test_largepages(void)
3763 if (!pGetLargePageMinimum
) {
3764 skip("No GetLargePageMinimum support.\n");
3767 size
= pGetLargePageMinimum();
3769 ok((size
== 0) || (size
== 2*1024*1024) || (size
== 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size
);
3772 struct proc_thread_attr
3779 struct _PROC_THREAD_ATTRIBUTE_LIST
3781 DWORD mask
; /* bitmask of items in list */
3782 DWORD size
; /* max number of items in list */
3783 DWORD count
; /* number of items in list */
3786 struct proc_thread_attr attrs
[10];
3789 static void test_ProcThreadAttributeList(void)
3792 SIZE_T size
, needed
;
3794 struct _PROC_THREAD_ATTRIBUTE_LIST list
, expect_list
;
3797 if (!pInitializeProcThreadAttributeList
)
3799 win_skip("No support for ProcThreadAttributeList\n");
3803 for (i
= 0; i
<= 10; i
++)
3805 needed
= FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST
, attrs
[i
]);
3806 ret
= pInitializeProcThreadAttributeList(NULL
, i
, 0, &size
);
3807 ok(!ret
, "got %d\n", ret
);
3808 if(i
>= 4 && GetLastError() == ERROR_INVALID_PARAMETER
) /* Vista only allows a maximium of 3 slots */
3810 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d\n", GetLastError());
3811 ok(size
== needed
, "%d: got %ld expect %ld\n", i
, size
, needed
);
3813 memset(&list
, 0xcc, sizeof(list
));
3814 ret
= pInitializeProcThreadAttributeList(&list
, i
, 0, &size
);
3815 ok(ret
, "got %d\n", ret
);
3816 ok(list
.mask
== 0, "%d: got %08x\n", i
, list
.mask
);
3817 ok(list
.size
== i
, "%d: got %08x\n", i
, list
.size
);
3818 ok(list
.count
== 0, "%d: got %08x\n", i
, list
.count
);
3819 ok(list
.unk
== 0, "%d: got %08lx\n", i
, list
.unk
);
3822 memset(handles
, 0, sizeof(handles
));
3823 memset(&expect_list
, 0xcc, sizeof(expect_list
));
3824 expect_list
.mask
= 0;
3825 expect_list
.size
= i
- 1;
3826 expect_list
.count
= 0;
3827 expect_list
.unk
= 0;
3829 ret
= pUpdateProcThreadAttribute(&list
, 0, 0xcafe, handles
, sizeof(PROCESSOR_NUMBER
), NULL
, NULL
);
3830 ok(!ret
, "got %d\n", ret
);
3831 ok(GetLastError() == ERROR_NOT_SUPPORTED
, "got %d\n", GetLastError());
3833 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]) / 2, NULL
, NULL
);
3834 ok(!ret
, "got %d\n", ret
);
3835 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %d\n", GetLastError());
3837 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]) * 2, NULL
, NULL
);
3838 ok(!ret
, "got %d\n", ret
);
3839 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %d\n", GetLastError());
3841 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]), NULL
, NULL
);
3842 ok(ret
, "got %d\n", ret
);
3844 expect_list
.mask
|= 1 << ProcThreadAttributeParentProcess
;
3845 expect_list
.attrs
[0].attr
= PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
;
3846 expect_list
.attrs
[0].size
= sizeof(handles
[0]);
3847 expect_list
.attrs
[0].value
= handles
;
3848 expect_list
.count
++;
3850 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]), NULL
, NULL
);
3851 ok(!ret
, "got %d\n", ret
);
3852 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS
, "got %d\n", GetLastError());
3854 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
) - 1, NULL
, NULL
);
3855 ok(!ret
, "got %d\n", ret
);
3856 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %d\n", GetLastError());
3858 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
), NULL
, NULL
);
3859 ok(ret
, "got %d\n", ret
);
3861 expect_list
.mask
|= 1 << ProcThreadAttributeHandleList
;
3862 expect_list
.attrs
[1].attr
= PROC_THREAD_ATTRIBUTE_HANDLE_LIST
;
3863 expect_list
.attrs
[1].size
= sizeof(handles
);
3864 expect_list
.attrs
[1].value
= handles
;
3865 expect_list
.count
++;
3867 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
), NULL
, NULL
);
3868 ok(!ret
, "got %d\n", ret
);
3869 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS
, "got %d\n", GetLastError());
3871 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR
, handles
, sizeof(PROCESSOR_NUMBER
), NULL
, NULL
);
3872 ok(ret
|| GetLastError() == ERROR_NOT_SUPPORTED
, "got %d gle %d\n", ret
, GetLastError());
3876 expect_list
.mask
|= 1 << ProcThreadAttributeIdealProcessor
;
3877 expect_list
.attrs
[2].attr
= PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR
;
3878 expect_list
.attrs
[2].size
= sizeof(PROCESSOR_NUMBER
);
3879 expect_list
.attrs
[2].value
= handles
;
3880 expect_list
.count
++;
3883 ok(!memcmp(&list
, &expect_list
, size
), "mismatch\n");
3885 pDeleteProcThreadAttributeList(&list
);
3888 static void test_GetActiveProcessorCount(void)
3892 if (!pGetActiveProcessorCount
)
3894 win_skip("GetActiveProcessorCount not available, skipping test\n");
3898 count
= pGetActiveProcessorCount(0);
3899 ok(count
, "GetActiveProcessorCount failed, error %u\n", GetLastError());
3901 /* Test would fail on systems with more than 6400 processors */
3902 SetLastError(0xdeadbeef);
3903 count
= pGetActiveProcessorCount(101);
3904 ok(count
== 0, "Expeced GetActiveProcessorCount to fail\n");
3905 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3912 ok(b
, "Basic init of CreateProcess test\n");
3917 if (!strcmp(myARGV
[2], "dump") && myARGC
>= 4)
3919 doChild(myARGV
[3], (myARGC
>= 5) ? myARGV
[4] : NULL
);
3922 else if (!strcmp(myARGV
[2], "wait"))
3925 ok(0, "Child process not killed\n");
3928 else if (!strcmp(myARGV
[2], "exit"))
3933 else if (!strcmp(myARGV
[2], "nested") && myARGC
>= 4)
3935 char buffer
[MAX_PATH
];
3936 STARTUPINFOA startup
;
3937 PROCESS_INFORMATION info
;
3939 memset(&startup
, 0, sizeof(startup
));
3940 startup
.cb
= sizeof(startup
);
3941 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3942 startup
.wShowWindow
= SW_SHOWNORMAL
;
3944 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, myARGV
[3]);
3945 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
3946 CloseHandle(info
.hProcess
);
3947 CloseHandle(info
.hThread
);
3951 ok(0, "Unexpected command %s\n", myARGV
[2]);
3955 test_process_info();
3956 test_TerminateProcess();
3963 test_DebuggingFlag();
3967 test_GetProcessVersion();
3968 test_GetProcessImageFileNameA();
3969 test_QueryFullProcessImageNameA();
3970 test_QueryFullProcessImageNameW();
3972 test_IsWow64Process();
3974 test_RegistryQuota();
3975 test_DuplicateHandle();
3976 test_StartupNoConsole();
3977 test_DetachConsoleHandles();
3978 test_DetachStdHandles();
3979 test_GetNumaProcessorNode();
3980 test_session_info();
3981 test_GetLogicalProcessorInformationEx();
3982 test_GetActiveProcessorCount();
3984 test_ProcThreadAttributeList();
3985 test_SuspendProcessState();
3986 test_SuspendProcessNewThread();
3988 /* things that can be tested:
3989 * lookup: check the way program to be executed is searched
3990 * handles: check the handle inheritance stuff (+sec options)
3991 * console: check if console creation parameters work
3994 if (!pCreateJobObjectW
)
3996 win_skip("No job object support\n");
4000 test_IsProcessInJob();
4001 test_TerminateJobObject();
4002 test_QueryInformationJobObject();
4003 test_CompletionPort();
4004 test_KillOnJobClose();
4005 test_WaitForJobObject();
4006 job
= test_AddSelfToJob();
4007 test_jobInheritance(job
);
4008 test_BreakawayOk(job
);