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
35 #include "wine/winternl.h"
38 #include "wine/test.h"
40 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
41 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
42 /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
43 #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
45 #define expect_eq_d(expected, actual) \
47 int value = (actual); \
48 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
51 #define expect_eq_s(expected, actual) \
53 LPCSTR value = (actual); \
54 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
57 #define expect_eq_ws_i(expected, actual) \
59 LPCWSTR value = (actual); \
60 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
61 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
64 static HINSTANCE hkernel32
, hntdll
;
65 static void (WINAPI
*pGetNativeSystemInfo
)(LPSYSTEM_INFO
);
66 static BOOL (WINAPI
*pGetSystemRegistryQuota
)(PDWORD
, PDWORD
);
67 static BOOL (WINAPI
*pIsWow64Process
)(HANDLE
,PBOOL
);
68 static LPVOID (WINAPI
*pVirtualAllocEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
, DWORD
);
69 static BOOL (WINAPI
*pVirtualFreeEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
);
70 static BOOL (WINAPI
*pQueryFullProcessImageNameA
)(HANDLE hProcess
, DWORD dwFlags
, LPSTR lpExeName
, PDWORD lpdwSize
);
71 static BOOL (WINAPI
*pQueryFullProcessImageNameW
)(HANDLE hProcess
, DWORD dwFlags
, LPWSTR lpExeName
, PDWORD lpdwSize
);
72 static DWORD (WINAPI
*pK32GetProcessImageFileNameA
)(HANDLE
,LPSTR
,DWORD
);
73 static HANDLE (WINAPI
*pCreateJobObjectW
)(LPSECURITY_ATTRIBUTES sa
, LPCWSTR name
);
74 static BOOL (WINAPI
*pAssignProcessToJobObject
)(HANDLE job
, HANDLE process
);
75 static BOOL (WINAPI
*pIsProcessInJob
)(HANDLE process
, HANDLE job
, PBOOL result
);
76 static BOOL (WINAPI
*pTerminateJobObject
)(HANDLE job
, UINT exit_code
);
77 static BOOL (WINAPI
*pQueryInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
, LPDWORD ret_len
);
78 static BOOL (WINAPI
*pSetInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
);
79 static HANDLE (WINAPI
*pCreateIoCompletionPort
)(HANDLE file
, HANDLE existing_port
, ULONG_PTR key
, DWORD threads
);
80 static BOOL (WINAPI
*pGetNumaProcessorNode
)(UCHAR
, PUCHAR
);
81 static NTSTATUS (WINAPI
*pNtQueryInformationProcess
)(HANDLE
, PROCESSINFOCLASS
, PVOID
, ULONG
, PULONG
);
82 static BOOL (WINAPI
*pProcessIdToSessionId
)(DWORD
,DWORD
*);
83 static DWORD (WINAPI
*pWTSGetActiveConsoleSessionId
)(void);
84 static HANDLE (WINAPI
*pCreateToolhelp32Snapshot
)(DWORD
, DWORD
);
85 static BOOL (WINAPI
*pProcess32First
)(HANDLE
, PROCESSENTRY32
*);
86 static BOOL (WINAPI
*pProcess32Next
)(HANDLE
, PROCESSENTRY32
*);
87 static BOOL (WINAPI
*pThread32First
)(HANDLE
, THREADENTRY32
*);
88 static BOOL (WINAPI
*pThread32Next
)(HANDLE
, THREADENTRY32
*);
89 static BOOL (WINAPI
*pGetLogicalProcessorInformationEx
)(LOGICAL_PROCESSOR_RELATIONSHIP
,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*,DWORD
*);
90 static SIZE_T (WINAPI
*pGetLargePageMinimum
)(void);
92 /* ############################### */
93 static char base
[MAX_PATH
];
94 static char selfname
[MAX_PATH
];
96 static char resfile
[MAX_PATH
];
101 /* As some environment variables get very long on Unix, we only test for
102 * the first 127 bytes.
103 * Note that increasing this value past 256 may exceed the buffer size
104 * limitations of the *Profile functions (at least on Wine).
106 #define MAX_LISTED_ENV_VAR 128
108 /* ---------------- portable memory allocation thingie */
110 static char memory
[1024*256];
111 static char* memory_index
= memory
;
113 static char* grab_memory(size_t len
)
115 char* ret
= memory_index
;
117 len
= (len
+ 3) & ~3;
119 assert(memory_index
<= memory
+ sizeof(memory
));
123 static void release_memory(void)
125 memory_index
= memory
;
128 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
130 static const char* encodeA(const char* str
)
136 len
= strlen(str
) + 1;
137 ptr
= grab_memory(len
* 2 + 1);
138 for (i
= 0; i
< len
; i
++)
139 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
144 static const char* encodeW(const WCHAR
* str
)
150 len
= lstrlenW(str
) + 1;
151 ptr
= grab_memory(len
* 4 + 1);
153 for (i
= 0; i
< len
; i
++)
154 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
159 static unsigned decode_char(char c
)
161 if (c
>= '0' && c
<= '9') return c
- '0';
162 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
163 assert(c
>= 'A' && c
<= 'F');
167 static char* decodeA(const char* str
)
172 len
= strlen(str
) / 2;
173 if (!len
--) return NULL
;
174 ptr
= grab_memory(len
+ 1);
175 for (i
= 0; i
< len
; i
++)
176 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
181 /* This will be needed to decode Unicode strings saved by the child process
182 * when we test Unicode functions.
184 static WCHAR
* decodeW(const char* str
)
190 len
= strlen(str
) / 4;
191 if (!len
--) return NULL
;
192 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
193 for (i
= 0; i
< len
; i
++)
194 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
195 (decode_char(str
[4 * i
+ 1]) << 8) |
196 (decode_char(str
[4 * i
+ 2]) << 4) |
197 (decode_char(str
[4 * i
+ 3]) << 0);
202 /******************************************************************
205 * generates basic information like:
206 * base: absolute path to curr dir
207 * selfname: the way to reinvoke ourselves
208 * exename: executable without the path
209 * function-pointers, which are not implemented in all windows versions
211 static BOOL
init(void)
215 myARGC
= winetest_get_mainargs( &myARGV
);
216 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return FALSE
;
217 strcpy(selfname
, myARGV
[0]);
219 /* Strip the path of selfname */
220 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
221 else exename
= selfname
;
223 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
225 hkernel32
= GetModuleHandleA("kernel32");
226 hntdll
= GetModuleHandleA("ntdll.dll");
228 pNtQueryInformationProcess
= (void *)GetProcAddress(hntdll
, "NtQueryInformationProcess");
230 pGetNativeSystemInfo
= (void *) GetProcAddress(hkernel32
, "GetNativeSystemInfo");
231 pGetSystemRegistryQuota
= (void *) GetProcAddress(hkernel32
, "GetSystemRegistryQuota");
232 pIsWow64Process
= (void *) GetProcAddress(hkernel32
, "IsWow64Process");
233 pVirtualAllocEx
= (void *) GetProcAddress(hkernel32
, "VirtualAllocEx");
234 pVirtualFreeEx
= (void *) GetProcAddress(hkernel32
, "VirtualFreeEx");
235 pQueryFullProcessImageNameA
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameA");
236 pQueryFullProcessImageNameW
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameW");
237 pK32GetProcessImageFileNameA
= (void *) GetProcAddress(hkernel32
, "K32GetProcessImageFileNameA");
238 pCreateJobObjectW
= (void *)GetProcAddress(hkernel32
, "CreateJobObjectW");
239 pAssignProcessToJobObject
= (void *)GetProcAddress(hkernel32
, "AssignProcessToJobObject");
240 pIsProcessInJob
= (void *)GetProcAddress(hkernel32
, "IsProcessInJob");
241 pTerminateJobObject
= (void *)GetProcAddress(hkernel32
, "TerminateJobObject");
242 pQueryInformationJobObject
= (void *)GetProcAddress(hkernel32
, "QueryInformationJobObject");
243 pSetInformationJobObject
= (void *)GetProcAddress(hkernel32
, "SetInformationJobObject");
244 pCreateIoCompletionPort
= (void *)GetProcAddress(hkernel32
, "CreateIoCompletionPort");
245 pGetNumaProcessorNode
= (void *)GetProcAddress(hkernel32
, "GetNumaProcessorNode");
246 pProcessIdToSessionId
= (void *)GetProcAddress(hkernel32
, "ProcessIdToSessionId");
247 pWTSGetActiveConsoleSessionId
= (void *)GetProcAddress(hkernel32
, "WTSGetActiveConsoleSessionId");
248 pCreateToolhelp32Snapshot
= (void *)GetProcAddress(hkernel32
, "CreateToolhelp32Snapshot");
249 pProcess32First
= (void *)GetProcAddress(hkernel32
, "Process32First");
250 pProcess32Next
= (void *)GetProcAddress(hkernel32
, "Process32Next");
251 pThread32First
= (void *)GetProcAddress(hkernel32
, "Thread32First");
252 pThread32Next
= (void *)GetProcAddress(hkernel32
, "Thread32Next");
253 pGetLogicalProcessorInformationEx
= (void *)GetProcAddress(hkernel32
, "GetLogicalProcessorInformationEx");
254 pGetLargePageMinimum
= (void *)GetProcAddress(hkernel32
, "GetLargePageMinimum");
259 /******************************************************************
262 * generates an absolute file_name for temporary file
265 static void get_file_name(char* buf
)
270 GetTempPathA(sizeof(path
), path
);
271 GetTempFileNameA(path
, "wt", 0, buf
);
274 /******************************************************************
275 * static void childPrintf
278 static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h
, const char* fmt
, ...)
281 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
284 va_start(valist
, fmt
);
285 vsprintf(buffer
, fmt
, valist
);
287 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
291 /******************************************************************
294 * output most of the information in the child process
296 static void doChild(const char* file
, const char* option
)
298 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
302 char *ptrA
, *ptrA_save
;
303 WCHAR
*ptrW
, *ptrW_save
;
305 WCHAR bufW
[MAX_PATH
];
306 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
311 if (hFile
== INVALID_HANDLE_VALUE
) return;
313 /* output of startup info (Ansi) */
314 GetStartupInfoA(&siA
);
316 "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
317 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
318 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
319 "dwFlags=%u\nwShowWindow=%u\n"
320 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
321 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
322 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
323 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
324 siA
.dwFlags
, siA
.wShowWindow
,
325 (DWORD_PTR
)siA
.hStdInput
, (DWORD_PTR
)siA
.hStdOutput
, (DWORD_PTR
)siA
.hStdError
);
327 /* check the console handles in the TEB */
328 childPrintf(hFile
, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
329 (DWORD_PTR
)params
->hStdInput
, (DWORD_PTR
)params
->hStdOutput
,
330 (DWORD_PTR
)params
->hStdError
);
332 /* since GetStartupInfoW is only implemented in win2k,
333 * zero out before calling so we can notice the difference
335 memset(&siW
, 0, sizeof(siW
));
336 GetStartupInfoW(&siW
);
338 "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
339 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
340 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
341 "dwFlags=%u\nwShowWindow=%u\n"
342 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
343 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
344 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
345 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
346 siW
.dwFlags
, siW
.wShowWindow
,
347 (DWORD_PTR
)siW
.hStdInput
, (DWORD_PTR
)siW
.hStdOutput
, (DWORD_PTR
)siW
.hStdError
);
350 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
351 for (i
= 0; i
< myARGC
; i
++)
353 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
355 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
356 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
358 /* output toolhelp information */
359 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
360 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
361 memset(&pe
, 0, sizeof(pe
));
362 pe
.dwSize
= sizeof(pe
);
363 if (pProcess32First(snapshot
, &pe
))
365 while (pe
.th32ProcessID
!= GetCurrentProcessId())
366 if (!pProcess32Next(snapshot
, &pe
)) break;
368 CloseHandle(snapshot
);
369 ok(pe
.th32ProcessID
== GetCurrentProcessId(), "failed to find current process in snapshot\n");
371 "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n"
372 "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n"
373 "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n",
374 pe
.cntUsage
, pe
.th32DefaultHeapID
, pe
.th32ModuleID
,
375 pe
.cntThreads
, pe
.th32ParentProcessID
, pe
.pcPriClassBase
,
376 pe
.dwFlags
, encodeA(pe
.szExeFile
));
378 /* output of environment (Ansi) */
379 ptrA_save
= ptrA
= GetEnvironmentStringsA();
382 char env_var
[MAX_LISTED_ENV_VAR
];
384 childPrintf(hFile
, "[EnvironmentA]\n");
388 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
389 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
391 ptrA
+= strlen(ptrA
) + 1;
393 childPrintf(hFile
, "len=%d\n\n", i
);
394 FreeEnvironmentStringsA(ptrA_save
);
397 /* output of environment (Unicode) */
398 ptrW_save
= ptrW
= GetEnvironmentStringsW();
401 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
403 childPrintf(hFile
, "[EnvironmentW]\n");
407 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
408 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
409 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
411 ptrW
+= lstrlenW(ptrW
) + 1;
413 childPrintf(hFile
, "len=%d\n\n", i
);
414 FreeEnvironmentStringsW(ptrW_save
);
417 childPrintf(hFile
, "[Misc]\n");
418 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
419 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
420 if (GetCurrentDirectoryW(sizeof(bufW
) / sizeof(bufW
[0]), bufW
))
421 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
422 childPrintf(hFile
, "\n");
424 if (option
&& strcmp(option
, "console") == 0)
426 CONSOLE_SCREEN_BUFFER_INFO sbi
;
427 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
428 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
429 DWORD modeIn
, modeOut
;
431 childPrintf(hFile
, "[Console]\n");
432 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
434 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
435 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
436 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
437 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
438 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
439 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
441 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
442 GetConsoleCP(), GetConsoleOutputCP());
443 if (GetConsoleMode(hConIn
, &modeIn
))
444 childPrintf(hFile
, "InputMode=%u\n", modeIn
);
445 if (GetConsoleMode(hConOut
, &modeOut
))
446 childPrintf(hFile
, "OutputMode=%u\n", modeOut
);
448 /* now that we have written all relevant information, let's change it */
449 SetLastError(0xdeadbeef);
450 ret
= SetConsoleCP(1252);
451 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
453 win_skip("Setting the codepage is not implemented\n");
457 ok(ret
, "Setting CP\n");
458 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
461 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
462 ok( ret
, "Setting mode (%d)\n", GetLastError());
463 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
464 ok( ret
, "Setting mode (%d)\n", GetLastError());
465 sbi
.dwCursorPosition
.X
^= 1;
466 sbi
.dwCursorPosition
.Y
^= 1;
467 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
468 ok( ret
, "Setting cursor position (%d)\n", GetLastError());
470 if (option
&& strcmp(option
, "stdhandle") == 0)
472 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
473 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
475 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
480 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
481 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
482 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
486 if (option
&& strcmp(option
, "exit_code") == 0)
488 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
496 static char* getChildString(const char* sect
, const char* key
)
498 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
501 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
502 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
503 assert(!(strlen(buf
) & 1));
508 static WCHAR
* getChildStringW(const char* sect
, const char* key
)
510 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
513 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
514 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
515 assert(!(strlen(buf
) & 1));
520 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
521 * others... (windows uses stricmp while Un*x uses strcasecmp...)
523 static int wtstrcasecmp(const char* p1
, const char* p2
)
528 while (c1
== c2
&& c1
)
530 c1
= *p1
++; c2
= *p2
++;
533 c1
= toupper(c1
); c2
= toupper(c2
);
539 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
541 if (!s1
&& !s2
) return 0;
544 return (sensitive
) ? strcmp(s1
, s2
) : wtstrcasecmp(s1
, s2
);
547 static void ok_child_string( int line
, const char *sect
, const char *key
,
548 const char *expect
, int sensitive
)
550 char* result
= getChildString( sect
, key
);
551 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
552 sect
, key
, expect
? expect
: "(null)", result
);
555 static void ok_child_stringWA( int line
, const char *sect
, const char *key
,
556 const char *expect
, int sensitive
)
561 WCHAR
* result
= getChildStringW( sect
, key
);
563 len
= MultiByteToWideChar( CP_ACP
, 0, expect
, -1, NULL
, 0);
564 expectW
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
565 MultiByteToWideChar( CP_ACP
, 0, expect
, -1, expectW
, len
);
567 len
= WideCharToMultiByte( CP_ACP
, 0, result
, -1, NULL
, 0, NULL
, NULL
);
568 resultA
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(CHAR
));
569 WideCharToMultiByte( CP_ACP
, 0, result
, -1, resultA
, len
, NULL
, NULL
);
572 ok_(__FILE__
, line
)( lstrcmpW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
573 sect
, key
, expect
? expect
: "(null)", resultA
);
575 ok_(__FILE__
, line
)( lstrcmpiW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
576 sect
, key
, expect
? expect
: "(null)", resultA
);
577 HeapFree(GetProcessHeap(),0,expectW
);
578 HeapFree(GetProcessHeap(),0,resultA
);
581 static void ok_child_int( int line
, const char *sect
, const char *key
, UINT expect
)
583 UINT result
= GetPrivateProfileIntA( sect
, key
, !expect
, resfile
);
584 ok_(__FILE__
, line
)( result
== expect
, "%s:%s expected %u, but got %u\n", sect
, key
, expect
, result
);
587 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
588 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
589 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
590 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
592 static void test_Startup(void)
594 char buffer
[MAX_PATH
];
595 PROCESS_INFORMATION info
;
596 STARTUPINFOA startup
,si
;
598 static CHAR title
[] = "I'm the title string",
599 desktop
[] = "winsta0\\default",
602 /* let's start simplistic */
603 memset(&startup
, 0, sizeof(startup
));
604 startup
.cb
= sizeof(startup
);
605 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
606 startup
.wShowWindow
= SW_SHOWNORMAL
;
608 get_file_name(resfile
);
609 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
610 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
611 /* wait for child to terminate */
612 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
613 /* child process has changed result file, so let profile functions know about it */
614 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
616 GetStartupInfoA(&si
);
617 okChildInt("StartupInfoA", "cb", startup
.cb
);
618 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
619 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
620 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
621 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
622 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
623 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
624 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
625 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
626 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
627 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
629 assert(DeleteFileA(resfile
) != 0);
631 /* not so simplistic now */
632 memset(&startup
, 0, sizeof(startup
));
633 startup
.cb
= sizeof(startup
);
634 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
635 startup
.wShowWindow
= SW_SHOWNORMAL
;
636 startup
.lpTitle
= title
;
637 startup
.lpDesktop
= desktop
;
638 startup
.dwXCountChars
= 0x12121212;
639 startup
.dwYCountChars
= 0x23232323;
640 startup
.dwX
= 0x34343434;
641 startup
.dwY
= 0x45454545;
642 startup
.dwXSize
= 0x56565656;
643 startup
.dwYSize
= 0x67676767;
644 startup
.dwFillAttribute
= 0xA55A;
646 get_file_name(resfile
);
647 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
648 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
649 /* wait for child to terminate */
650 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
651 /* child process has changed result file, so let profile functions know about it */
652 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
654 okChildInt("StartupInfoA", "cb", startup
.cb
);
655 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
656 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
657 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
658 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
659 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
660 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
661 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
662 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
663 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
664 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
665 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
667 assert(DeleteFileA(resfile
) != 0);
669 /* not so simplistic now */
670 memset(&startup
, 0, sizeof(startup
));
671 startup
.cb
= sizeof(startup
);
672 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
673 startup
.wShowWindow
= SW_SHOWNORMAL
;
674 startup
.lpTitle
= title
;
675 startup
.lpDesktop
= NULL
;
676 startup
.dwXCountChars
= 0x12121212;
677 startup
.dwYCountChars
= 0x23232323;
678 startup
.dwX
= 0x34343434;
679 startup
.dwY
= 0x45454545;
680 startup
.dwXSize
= 0x56565656;
681 startup
.dwYSize
= 0x67676767;
682 startup
.dwFillAttribute
= 0xA55A;
684 get_file_name(resfile
);
685 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
686 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
687 /* wait for child to terminate */
688 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
689 /* child process has changed result file, so let profile functions know about it */
690 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
692 okChildInt("StartupInfoA", "cb", startup
.cb
);
693 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
694 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
695 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
696 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
697 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
698 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
699 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
700 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
701 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
702 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
703 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
705 assert(DeleteFileA(resfile
) != 0);
707 /* not so simplistic now */
708 memset(&startup
, 0, sizeof(startup
));
709 startup
.cb
= sizeof(startup
);
710 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
711 startup
.wShowWindow
= SW_SHOWNORMAL
;
712 startup
.lpTitle
= title
;
713 startup
.lpDesktop
= empty
;
714 startup
.dwXCountChars
= 0x12121212;
715 startup
.dwYCountChars
= 0x23232323;
716 startup
.dwX
= 0x34343434;
717 startup
.dwY
= 0x45454545;
718 startup
.dwXSize
= 0x56565656;
719 startup
.dwYSize
= 0x67676767;
720 startup
.dwFillAttribute
= 0xA55A;
722 get_file_name(resfile
);
723 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
724 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
725 /* wait for child to terminate */
726 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
727 /* child process has changed result file, so let profile functions know about it */
728 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
730 okChildInt("StartupInfoA", "cb", startup
.cb
);
731 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
732 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
733 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
734 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
735 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
736 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
737 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
738 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
739 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
740 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
741 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
743 assert(DeleteFileA(resfile
) != 0);
745 /* not so simplistic now */
746 memset(&startup
, 0, sizeof(startup
));
747 startup
.cb
= sizeof(startup
);
748 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
749 startup
.wShowWindow
= SW_SHOWNORMAL
;
750 startup
.lpTitle
= NULL
;
751 startup
.lpDesktop
= desktop
;
752 startup
.dwXCountChars
= 0x12121212;
753 startup
.dwYCountChars
= 0x23232323;
754 startup
.dwX
= 0x34343434;
755 startup
.dwY
= 0x45454545;
756 startup
.dwXSize
= 0x56565656;
757 startup
.dwYSize
= 0x67676767;
758 startup
.dwFillAttribute
= 0xA55A;
760 get_file_name(resfile
);
761 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
762 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
763 /* wait for child to terminate */
764 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
765 /* child process has changed result file, so let profile functions know about it */
766 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
768 okChildInt("StartupInfoA", "cb", startup
.cb
);
769 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
770 result
= getChildString( "StartupInfoA", "lpTitle" );
771 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
772 "expected '%s' or null, got '%s'\n", selfname
, result
);
773 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
774 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
775 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
776 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
777 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
778 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
779 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
780 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
781 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
783 assert(DeleteFileA(resfile
) != 0);
785 /* not so simplistic now */
786 memset(&startup
, 0, sizeof(startup
));
787 startup
.cb
= sizeof(startup
);
788 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
789 startup
.wShowWindow
= SW_SHOWNORMAL
;
790 startup
.lpTitle
= empty
;
791 startup
.lpDesktop
= desktop
;
792 startup
.dwXCountChars
= 0x12121212;
793 startup
.dwYCountChars
= 0x23232323;
794 startup
.dwX
= 0x34343434;
795 startup
.dwY
= 0x45454545;
796 startup
.dwXSize
= 0x56565656;
797 startup
.dwYSize
= 0x67676767;
798 startup
.dwFillAttribute
= 0xA55A;
800 get_file_name(resfile
);
801 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
802 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
803 /* wait for child to terminate */
804 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
805 /* child process has changed result file, so let profile functions know about it */
806 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
808 okChildInt("StartupInfoA", "cb", startup
.cb
);
809 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
810 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
811 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
812 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
813 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
814 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
815 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
816 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
817 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
818 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
819 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
821 assert(DeleteFileA(resfile
) != 0);
823 /* not so simplistic now */
824 memset(&startup
, 0, sizeof(startup
));
825 startup
.cb
= sizeof(startup
);
826 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
827 startup
.wShowWindow
= SW_SHOWNORMAL
;
828 startup
.lpTitle
= empty
;
829 startup
.lpDesktop
= empty
;
830 startup
.dwXCountChars
= 0x12121212;
831 startup
.dwYCountChars
= 0x23232323;
832 startup
.dwX
= 0x34343434;
833 startup
.dwY
= 0x45454545;
834 startup
.dwXSize
= 0x56565656;
835 startup
.dwYSize
= 0x67676767;
836 startup
.dwFillAttribute
= 0xA55A;
838 get_file_name(resfile
);
839 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
840 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
841 /* wait for child to terminate */
842 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
843 /* child process has changed result file, so let profile functions know about it */
844 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
846 okChildInt("StartupInfoA", "cb", startup
.cb
);
847 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
848 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
849 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
850 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
851 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
852 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
853 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
854 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
855 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
856 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
857 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
859 assert(DeleteFileA(resfile
) != 0);
861 /* TODO: test for A/W and W/A and W/W */
864 static void test_CommandLine(void)
866 char buffer
[MAX_PATH
], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
867 char buffer2
[MAX_PATH
];
868 PROCESS_INFORMATION info
;
869 STARTUPINFOA startup
;
872 memset(&startup
, 0, sizeof(startup
));
873 startup
.cb
= sizeof(startup
);
874 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
875 startup
.wShowWindow
= SW_SHOWNORMAL
;
878 get_file_name(resfile
);
879 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
880 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
881 /* wait for child to terminate */
882 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
883 /* child process has changed result file, so let profile functions know about it */
884 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
886 okChildInt("Arguments", "argcA", 5);
887 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
888 okChildString("Arguments", "argvA5", NULL
);
889 okChildString("Arguments", "CommandLineA", buffer
);
891 assert(DeleteFileA(resfile
) != 0);
893 memset(&startup
, 0, sizeof(startup
));
894 startup
.cb
= sizeof(startup
);
895 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
896 startup
.wShowWindow
= SW_SHOWNORMAL
;
899 get_file_name(resfile
);
900 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname
, resfile
);
901 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
902 /* wait for child to terminate */
903 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
904 /* child process has changed result file, so let profile functions know about it */
905 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
907 okChildInt("Arguments", "argcA", 7);
908 okChildString("Arguments", "argvA4", "a\"b\\");
909 okChildString("Arguments", "argvA5", "c\"");
910 okChildString("Arguments", "argvA6", "d");
911 okChildString("Arguments", "argvA7", NULL
);
912 okChildString("Arguments", "CommandLineA", buffer
);
914 assert(DeleteFileA(resfile
) != 0);
916 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
917 get_file_name(resfile
);
918 /* Use exename to avoid buffer containing things like 'C:' */
919 sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
920 SetLastError(0xdeadbeef);
921 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
922 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
923 /* wait for child to terminate */
924 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
925 /* child process has changed result file, so let profile functions know about it */
926 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
927 sprintf(buffer
, "./%s", exename
);
928 okChildString("Arguments", "argvA0", buffer
);
930 assert(DeleteFileA(resfile
) != 0);
932 get_file_name(resfile
);
933 /* Use exename to avoid buffer containing things like 'C:' */
934 sprintf(buffer
, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
935 SetLastError(0xdeadbeef);
936 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
937 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
938 /* wait for child to terminate */
939 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
940 /* child process has changed result file, so let profile functions know about it */
941 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
942 sprintf(buffer
, ".\\%s", exename
);
943 okChildString("Arguments", "argvA0", buffer
);
945 assert(DeleteFileA(resfile
) != 0);
947 get_file_name(resfile
);
948 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
949 assert ( lpFilePart
!= 0);
950 *(lpFilePart
-1 ) = 0;
951 p
= strrchr(fullpath
, '\\');
952 /* Use exename to avoid buffer containing things like 'C:' */
953 if (p
) sprintf(buffer
, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p
, exename
, resfile
);
954 else sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
955 SetLastError(0xdeadbeef);
956 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
957 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
958 /* wait for child to terminate */
959 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
960 /* child process has changed result file, so let profile functions know about it */
961 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
962 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
963 else sprintf(buffer
, "./%s", exename
);
964 okChildString("Arguments", "argvA0", buffer
);
966 assert(DeleteFileA(resfile
) != 0);
969 get_file_name(resfile
);
970 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
971 assert ( lpFilePart
!= 0);
972 *(lpFilePart
-1 ) = 0;
973 p
= strrchr(fullpath
, '\\');
974 /* Use exename to avoid buffer containing things like 'C:' */
975 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
976 else sprintf(buffer
, "./%s", exename
);
977 sprintf(buffer2
, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile
);
978 SetLastError(0xdeadbeef);
979 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
980 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
981 /* wait for child to terminate */
982 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
983 /* child process has changed result file, so let profile functions know about it */
984 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
985 sprintf(buffer
, "tests/process.c dump %s", resfile
);
986 okChildString("Arguments", "argvA0", "dummy");
987 okChildString("Arguments", "CommandLineA", buffer2
);
988 okChildStringWA("Arguments", "CommandLineW", buffer2
);
990 assert(DeleteFileA(resfile
) != 0);
992 if (0) /* Test crashes on NT-based Windows. */
994 /* Test NULL application name and command line parameters. */
995 SetLastError(0xdeadbeef);
996 ret
= CreateProcessA(NULL
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
997 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
998 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
999 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1004 /* Test empty application name parameter. */
1005 SetLastError(0xdeadbeef);
1006 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1007 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1008 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
1009 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
1010 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
1011 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1015 /* Test empty application name and command line parameters. */
1016 SetLastError(0xdeadbeef);
1017 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1018 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1019 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
1020 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
1021 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
1022 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1024 /* Test empty command line parameter. */
1025 SetLastError(0xdeadbeef);
1026 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1027 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1028 ok(GetLastError() == ERROR_FILE_NOT_FOUND
||
1029 GetLastError() == ERROR_PATH_NOT_FOUND
/* NT4 */ ||
1030 GetLastError() == ERROR_BAD_PATHNAME
/* Win98 */ ||
1031 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7 */,
1032 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1034 strcpy(buffer
, "doesnotexist.exe");
1035 strcpy(buffer2
, "does not exist.exe");
1037 /* Test nonexistent application name. */
1038 SetLastError(0xdeadbeef);
1039 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1040 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1041 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1043 SetLastError(0xdeadbeef);
1044 ret
= CreateProcessA(buffer2
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1045 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1046 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1048 /* Test nonexistent command line parameter. */
1049 SetLastError(0xdeadbeef);
1050 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1051 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1052 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1054 SetLastError(0xdeadbeef);
1055 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1056 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1057 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1060 static void test_Directory(void)
1062 char buffer
[MAX_PATH
];
1063 PROCESS_INFORMATION info
;
1064 STARTUPINFOA startup
;
1065 char windir
[MAX_PATH
];
1066 static CHAR cmdline
[] = "winver.exe";
1068 memset(&startup
, 0, sizeof(startup
));
1069 startup
.cb
= sizeof(startup
);
1070 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1071 startup
.wShowWindow
= SW_SHOWNORMAL
;
1074 get_file_name(resfile
);
1075 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1076 GetWindowsDirectoryA( windir
, sizeof(windir
) );
1077 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
1078 /* wait for child to terminate */
1079 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1080 /* child process has changed result file, so let profile functions know about it */
1081 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1083 okChildIString("Misc", "CurrDirA", windir
);
1085 assert(DeleteFileA(resfile
) != 0);
1087 /* search PATH for the exe if directory is NULL */
1088 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1089 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
1091 /* if any directory is provided, don't search PATH, error on bad directory */
1092 SetLastError(0xdeadbeef);
1093 memset(&info
, 0, sizeof(info
));
1094 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
1095 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
1096 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1097 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
1100 static void test_Toolhelp(void)
1102 char buffer
[MAX_PATH
];
1103 STARTUPINFOA startup
;
1104 PROCESS_INFORMATION info
;
1105 HANDLE process
, thread
, snapshot
;
1111 memset(&startup
, 0, sizeof(startup
));
1112 startup
.cb
= sizeof(startup
);
1113 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1114 startup
.wShowWindow
= SW_SHOWNORMAL
;
1116 get_file_name(resfile
);
1117 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1118 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1119 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1120 CloseHandle(info
.hProcess
);
1121 CloseHandle(info
.hThread
);
1123 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1124 okChildInt("Toolhelp", "cntUsage", 0);
1125 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1126 okChildInt("Toolhelp", "th32ModuleID", 0);
1127 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1128 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1129 okChildInt("Toolhelp", "dwFlags", 0);
1132 DeleteFileA(resfile
);
1134 get_file_name(resfile
);
1135 sprintf(buffer
, "\"%s\" tests/process.c nested \"%s\"", selfname
, resfile
);
1136 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1137 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1139 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1140 ok(process
!= NULL
, "OpenProcess failed %u\n", GetLastError());
1141 CloseHandle(process
);
1143 CloseHandle(info
.hProcess
);
1144 CloseHandle(info
.hThread
);
1146 for (i
= 0; i
< 20; i
++)
1148 SetLastError(0xdeadbeef);
1149 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1150 ok(process
|| GetLastError() == ERROR_INVALID_PARAMETER
, "OpenProcess failed %u\n", GetLastError());
1151 if (!process
) break;
1152 CloseHandle(process
);
1155 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1156 ok(i
< 20 || broken(i
== 20), "process object not released\n");
1158 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
1159 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1160 memset(&pe
, 0, sizeof(pe
));
1161 pe
.dwSize
= sizeof(pe
);
1162 if (pProcess32First(snapshot
, &pe
))
1164 while (pe
.th32ParentProcessID
!= info
.dwProcessId
)
1165 if (!pProcess32Next(snapshot
, &pe
)) break;
1167 CloseHandle(snapshot
);
1168 ok(pe
.th32ParentProcessID
== info
.dwProcessId
, "failed to find nested child process\n");
1170 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, pe
.th32ProcessID
);
1171 ok(process
!= NULL
, "OpenProcess failed %u\n", GetLastError());
1173 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD
, 0);
1174 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1175 memset(&te
, 0, sizeof(te
));
1176 te
.dwSize
= sizeof(te
);
1177 if (pThread32First(snapshot
, &te
))
1179 while (te
.th32OwnerProcessID
!= pe
.th32ProcessID
)
1180 if (!pThread32Next(snapshot
, &te
)) break;
1182 CloseHandle(snapshot
);
1183 ok(te
.th32OwnerProcessID
== pe
.th32ProcessID
, "failed to find suspended thread\n");
1185 thread
= OpenThread(THREAD_ALL_ACCESS_NT4
, FALSE
, te
.th32ThreadID
);
1186 ok(thread
!= NULL
, "OpenThread failed %u\n", GetLastError());
1187 ret
= ResumeThread(thread
);
1188 ok(ret
== 1, "expected 1, got %u\n", ret
);
1189 CloseHandle(thread
);
1191 ok(WaitForSingleObject(process
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1192 CloseHandle(process
);
1194 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1195 okChildInt("Toolhelp", "cntUsage", 0);
1196 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1197 okChildInt("Toolhelp", "th32ModuleID", 0);
1198 okChildInt("Toolhelp", "th32ParentProcessID", info
.dwProcessId
);
1199 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1200 okChildInt("Toolhelp", "dwFlags", 0);
1203 DeleteFileA(resfile
);
1206 static BOOL
is_str_env_drive_dir(const char* str
)
1208 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1209 str
[3] == '=' && str
[4] == str
[1];
1212 /* compared expected child's environment (in gesA) from actual
1213 * environment our child got
1215 static void cmpEnvironment(const char* gesA
)
1223 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1225 /* now look each parent env in child */
1226 if ((ptrA
= gesA
) != NULL
)
1230 for (i
= 0; i
< clen
; i
++)
1232 sprintf(key
, "env%d", i
);
1233 res
= getChildString("EnvironmentA", key
);
1234 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1238 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1240 ptrA
+= strlen(ptrA
) + 1;
1244 /* and each child env in parent */
1245 for (i
= 0; i
< clen
; i
++)
1247 sprintf(key
, "env%d", i
);
1248 res
= getChildString("EnvironmentA", key
);
1249 if ((ptrA
= gesA
) != NULL
)
1253 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1255 ptrA
+= strlen(ptrA
) + 1;
1257 if (!*ptrA
) ptrA
= NULL
;
1260 if (!is_str_env_drive_dir(res
))
1262 found
= ptrA
!= NULL
;
1263 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1265 /* else => should also test we get the right per drive default directory here... */
1269 static void test_Environment(void)
1271 char buffer
[MAX_PATH
];
1272 PROCESS_INFORMATION info
;
1273 STARTUPINFOA startup
;
1281 memset(&startup
, 0, sizeof(startup
));
1282 startup
.cb
= sizeof(startup
);
1283 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1284 startup
.wShowWindow
= SW_SHOWNORMAL
;
1287 get_file_name(resfile
);
1288 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1289 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1290 /* wait for child to terminate */
1291 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1292 /* child process has changed result file, so let profile functions know about it */
1293 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1295 env
= GetEnvironmentStringsA();
1296 cmpEnvironment(env
);
1298 assert(DeleteFileA(resfile
) != 0);
1300 memset(&startup
, 0, sizeof(startup
));
1301 startup
.cb
= sizeof(startup
);
1302 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1303 startup
.wShowWindow
= SW_SHOWNORMAL
;
1306 get_file_name(resfile
);
1307 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1313 slen
= strlen(ptr
)+1;
1314 child_env_len
+= slen
;
1317 /* Add space for additional environment variables */
1318 child_env_len
+= 256;
1319 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1322 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1323 ptr
+= strlen(ptr
) + 1;
1324 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1325 ptr
+= strlen(ptr
) + 1;
1326 strcpy(ptr
, "FOO=BAR");
1327 ptr
+= strlen(ptr
) + 1;
1328 strcpy(ptr
, "BAR=FOOBAR");
1329 ptr
+= strlen(ptr
) + 1;
1330 /* copy all existing variables except:
1332 * - PATH (already set above)
1333 * - the directory definitions (=[A-Z]:=)
1335 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1337 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1338 strncmp(ptr2
, "WINELOADER=", 11) != 0 &&
1339 !is_str_env_drive_dir(ptr2
))
1342 ptr
+= strlen(ptr
) + 1;
1346 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1347 /* wait for child to terminate */
1348 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1349 /* child process has changed result file, so let profile functions know about it */
1350 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1352 cmpEnvironment(child_env
);
1354 HeapFree(GetProcessHeap(), 0, child_env
);
1355 FreeEnvironmentStringsA(env
);
1357 assert(DeleteFileA(resfile
) != 0);
1360 static void test_SuspendFlag(void)
1362 char buffer
[MAX_PATH
];
1363 PROCESS_INFORMATION info
;
1364 STARTUPINFOA startup
, us
;
1368 /* let's start simplistic */
1369 memset(&startup
, 0, sizeof(startup
));
1370 startup
.cb
= sizeof(startup
);
1371 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1372 startup
.wShowWindow
= SW_SHOWNORMAL
;
1374 get_file_name(resfile
);
1375 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1376 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1378 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1380 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1381 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1383 /* wait for child to terminate */
1384 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1385 /* child process has changed result file, so let profile functions know about it */
1386 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1388 GetStartupInfoA(&us
);
1390 okChildInt("StartupInfoA", "cb", startup
.cb
);
1391 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1392 result
= getChildString( "StartupInfoA", "lpTitle" );
1393 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1394 "expected '%s' or null, got '%s'\n", selfname
, result
);
1395 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1396 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1397 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1398 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1399 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1400 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1401 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1402 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1403 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1405 assert(DeleteFileA(resfile
) != 0);
1408 static void test_DebuggingFlag(void)
1410 char buffer
[MAX_PATH
];
1411 void *processbase
= NULL
;
1412 PROCESS_INFORMATION info
;
1413 STARTUPINFOA startup
, us
;
1418 /* let's start simplistic */
1419 memset(&startup
, 0, sizeof(startup
));
1420 startup
.cb
= sizeof(startup
);
1421 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1422 startup
.wShowWindow
= SW_SHOWNORMAL
;
1424 get_file_name(resfile
);
1425 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1426 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1428 /* get all startup events up to the entry point break exception */
1431 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1432 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1435 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1436 "first event: %d\n", de
.dwDebugEventCode
);
1437 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1439 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1440 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1441 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1442 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1444 ok(dbg
, "I have seen a debug event\n");
1445 /* wait for child to terminate */
1446 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1447 /* child process has changed result file, so let profile functions know about it */
1448 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1450 GetStartupInfoA(&us
);
1452 okChildInt("StartupInfoA", "cb", startup
.cb
);
1453 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1454 result
= getChildString( "StartupInfoA", "lpTitle" );
1455 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1456 "expected '%s' or null, got '%s'\n", selfname
, result
);
1457 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1458 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1459 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1460 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1461 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1462 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1463 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1464 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1465 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1467 assert(DeleteFileA(resfile
) != 0);
1470 static BOOL
is_console(HANDLE h
)
1472 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1475 static void test_Console(void)
1477 char buffer
[MAX_PATH
];
1478 PROCESS_INFORMATION info
;
1479 STARTUPINFOA startup
, us
;
1480 SECURITY_ATTRIBUTES sa
;
1481 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1482 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1483 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1485 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1486 const char* msg
= "This is a std-handle inheritance test.";
1488 BOOL run_tests
= TRUE
;
1491 memset(&startup
, 0, sizeof(startup
));
1492 startup
.cb
= sizeof(startup
);
1493 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1494 startup
.wShowWindow
= SW_SHOWNORMAL
;
1496 sa
.nLength
= sizeof(sa
);
1497 sa
.lpSecurityDescriptor
= NULL
;
1498 sa
.bInheritHandle
= TRUE
;
1500 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1501 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1503 /* first, we need to be sure we're attached to a console */
1504 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1506 /* we're not attached to a console, let's do it */
1508 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1509 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1511 /* now verify everything's ok */
1512 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1513 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1514 startup
.hStdError
= startup
.hStdOutput
;
1516 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1517 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
) &&
1518 GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console modes\n");
1519 cpIn
= GetConsoleCP();
1520 cpOut
= GetConsoleOutputCP();
1522 get_file_name(resfile
);
1523 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" console", selfname
, resfile
);
1524 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1526 /* wait for child to terminate */
1527 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1528 /* child process has changed result file, so let profile functions know about it */
1529 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1531 /* now get the modification the child has made, and resets parents expected values */
1532 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1533 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
) &&
1534 GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console modes\n");
1536 SetConsoleMode(startup
.hStdInput
, modeIn
);
1537 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1539 cpInC
= GetConsoleCP();
1540 cpOutC
= GetConsoleOutputCP();
1542 /* Try to set invalid CP */
1543 SetLastError(0xdeadbeef);
1544 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1545 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1546 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1547 "GetLastError: expecting %u got %u\n",
1548 ERROR_INVALID_PARAMETER
, GetLastError());
1549 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1553 SetLastError(0xdeadbeef);
1554 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1555 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1556 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1557 "GetLastError: expecting %u got %u\n",
1558 ERROR_INVALID_PARAMETER
, GetLastError());
1561 SetConsoleOutputCP(cpOut
);
1563 GetStartupInfoA(&us
);
1565 okChildInt("StartupInfoA", "cb", startup
.cb
);
1566 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1567 result
= getChildString( "StartupInfoA", "lpTitle" );
1568 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1569 "expected '%s' or null, got '%s'\n", selfname
, result
);
1570 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1571 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1572 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1573 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1574 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1575 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1576 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1577 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1578 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1580 /* check child correctly inherited the console */
1581 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1582 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1583 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1584 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1585 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1586 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1587 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1588 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1589 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1590 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1591 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1592 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1593 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1594 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1595 okChildInt("Console", "InputCP", cpIn
);
1596 okChildInt("Console", "OutputCP", cpOut
);
1597 okChildInt("Console", "InputMode", modeIn
);
1598 okChildInt("Console", "OutputMode", modeOut
);
1602 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1603 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1606 win_skip("Setting the codepage is not implemented\n");
1608 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1609 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1610 trace("cursor position(X): %d/%d\n",sbi
.dwCursorPosition
.X
, sbiC
.dwCursorPosition
.X
);
1611 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1614 assert(DeleteFileA(resfile
) != 0);
1616 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1617 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1618 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1619 "Duplicating as inheritable child-output pipe\n");
1620 CloseHandle(hChildOut
);
1622 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1623 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1624 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1625 "Duplicating as inheritable child-input pipe\n");
1626 CloseHandle(hChildIn
);
1628 memset(&startup
, 0, sizeof(startup
));
1629 startup
.cb
= sizeof(startup
);
1630 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1631 startup
.wShowWindow
= SW_SHOWNORMAL
;
1632 startup
.hStdInput
= hChildInInh
;
1633 startup
.hStdOutput
= hChildOutInh
;
1634 startup
.hStdError
= hChildOutInh
;
1636 get_file_name(resfile
);
1637 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname
, resfile
);
1638 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1639 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1640 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1642 msg_len
= strlen(msg
) + 1;
1643 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1644 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1645 memset(buffer
, 0, sizeof(buffer
));
1646 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1647 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1649 /* wait for child to terminate */
1650 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1651 /* child process has changed result file, so let profile functions know about it */
1652 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1654 okChildString("StdHandle", "msg", msg
);
1657 assert(DeleteFileA(resfile
) != 0);
1660 static void test_ExitCode(void)
1662 char buffer
[MAX_PATH
];
1663 PROCESS_INFORMATION info
;
1664 STARTUPINFOA startup
;
1667 /* let's start simplistic */
1668 memset(&startup
, 0, sizeof(startup
));
1669 startup
.cb
= sizeof(startup
);
1670 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1671 startup
.wShowWindow
= SW_SHOWNORMAL
;
1673 get_file_name(resfile
);
1674 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname
, resfile
);
1675 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1677 /* wait for child to terminate */
1678 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1679 /* child process has changed result file, so let profile functions know about it */
1680 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1682 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1683 okChildInt("ExitCode", "value", code
);
1686 assert(DeleteFileA(resfile
) != 0);
1689 static void test_OpenProcess(void)
1693 MEMORY_BASIC_INFORMATION info
;
1694 SIZE_T dummy
, read_bytes
;
1697 /* not exported in all windows versions */
1698 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1699 win_skip("VirtualAllocEx not found\n");
1703 /* without PROCESS_VM_OPERATION */
1704 hproc
= OpenProcess(PROCESS_ALL_ACCESS_NT4
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1705 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1707 SetLastError(0xdeadbeef);
1708 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1709 ok(!addr1
, "VirtualAllocEx should fail\n");
1710 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1713 win_skip("VirtualAllocEx not implemented\n");
1716 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1718 read_bytes
= 0xdeadbeef;
1719 SetLastError(0xdeadbeef);
1720 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1721 ok(ret
, "ReadProcessMemory error %d\n", GetLastError());
1722 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1726 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1727 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1729 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1730 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1732 /* without PROCESS_QUERY_INFORMATION */
1733 SetLastError(0xdeadbeef);
1734 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1735 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1736 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1738 /* without PROCESS_VM_READ */
1739 read_bytes
= 0xdeadbeef;
1740 SetLastError(0xdeadbeef);
1741 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1742 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1743 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1744 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1748 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1750 memset(&info
, 0xcc, sizeof(info
));
1751 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1752 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1754 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1755 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1756 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1757 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1758 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1759 /* NT reports Protect == 0 for a not committed memory block */
1760 ok(info
.Protect
== 0 /* NT */ ||
1761 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1762 "%x != PAGE_NOACCESS\n", info
.Protect
);
1763 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1765 SetLastError(0xdeadbeef);
1766 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1767 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1768 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1772 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
1775 SetLastError(0xdeadbeef);
1776 memset(&info
, 0xcc, sizeof(info
));
1777 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1778 if (read_bytes
) /* win8 */
1780 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1781 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1782 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1783 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1784 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1785 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1786 ok(info
.Protect
== 0, "%x != PAGE_NOACCESS\n", info
.Protect
);
1787 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1789 else /* before win8 */
1790 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1792 SetLastError(0xdeadbeef);
1793 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1794 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1795 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1800 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1803 static void test_GetProcessVersion(void)
1805 static char cmdline
[] = "winver.exe";
1806 PROCESS_INFORMATION pi
;
1810 SetLastError(0xdeadbeef);
1811 ret
= GetProcessVersion(0);
1812 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1814 SetLastError(0xdeadbeef);
1815 ret
= GetProcessVersion(GetCurrentProcessId());
1816 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1818 memset(&si
, 0, sizeof(si
));
1820 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1821 si
.wShowWindow
= SW_HIDE
;
1822 SetLastError(0xdeadbeef);
1823 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1824 ok(ret
, "CreateProcess error %u\n", GetLastError());
1826 SetLastError(0xdeadbeef);
1827 ret
= GetProcessVersion(pi
.dwProcessId
);
1828 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1830 SetLastError(0xdeadbeef);
1831 ret
= TerminateProcess(pi
.hProcess
, 0);
1832 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1834 CloseHandle(pi
.hProcess
);
1835 CloseHandle(pi
.hThread
);
1838 static void test_GetProcessImageFileNameA(void)
1841 CHAR process
[MAX_PATH
];
1842 static const char harddisk
[] = "\\Device\\HarddiskVolume";
1844 if (!pK32GetProcessImageFileNameA
)
1846 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1850 /* callers must guess the buffer size */
1851 SetLastError(0xdeadbeef);
1852 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL
, 0);
1853 ok(!rc
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
1854 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc
, GetLastError());
1857 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), process
, sizeof(process
));
1858 expect_eq_d(rc
, lstrlenA(process
));
1859 if (strncmp(process
, harddisk
, lstrlenA(harddisk
)))
1861 todo_wine
win_skip("%s is probably on a network share, skipping tests\n", process
);
1865 if (!pQueryFullProcessImageNameA
)
1866 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1869 CHAR image
[MAX_PATH
];
1872 length
= sizeof(image
);
1873 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE
, image
, &length
));
1874 expect_eq_d(length
, lstrlenA(image
));
1875 ok(lstrcmpiA(process
, image
) == 0, "expected '%s' to be equal to '%s'\n", process
, image
);
1879 static void test_QueryFullProcessImageNameA(void)
1881 #define INIT_STR "Just some words"
1883 CHAR buf
[MAX_PATH
], module
[MAX_PATH
];
1885 if (!pQueryFullProcessImageNameA
)
1887 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1892 SetLastError(0); /* old Windows don't reset it on success */
1893 size
= GetModuleFileNameA(NULL
, module
, sizeof(module
));
1894 ok(size
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
, "GetModuleFileName failed: %u le=%u\n", size
, GetLastError());
1896 /* get the buffer length without \0 terminator */
1897 length
= sizeof(buf
);
1898 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1899 expect_eq_d(length
, lstrlenA(buf
));
1900 ok((buf
[0] == '\\' && buf
[1] == '\\') ||
1901 lstrcmpiA(buf
, module
) == 0, "expected %s to match %s\n", buf
, module
);
1903 /* when the buffer is too small
1904 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1905 * - the size variable is not modified
1906 * tested with the biggest too small size
1909 sprintf(buf
,INIT_STR
);
1910 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1911 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1912 expect_eq_d(length
, size
);
1913 expect_eq_s(INIT_STR
, buf
);
1915 /* retest with smaller buffer size
1918 sprintf(buf
,INIT_STR
);
1919 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1920 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1921 expect_eq_d(4, size
);
1922 expect_eq_s(INIT_STR
, buf
);
1924 /* this is a difference between the ascii and the unicode version
1925 * the unicode version crashes when the size is big enough to hold
1926 * the result while the ascii version throws an error
1929 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1930 expect_eq_d(1024, size
);
1931 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1934 static void test_QueryFullProcessImageNameW(void)
1937 WCHAR module_name
[1024], device
[1024];
1938 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
1942 if (!pQueryFullProcessImageNameW
)
1944 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1948 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1950 /* GetCurrentProcess pseudo-handle */
1951 size
= sizeof(buf
) / sizeof(buf
[0]);
1952 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
1953 expect_eq_d(lstrlenW(buf
), size
);
1954 expect_eq_ws_i(buf
, module_name
);
1956 hSelf
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1958 size
= sizeof(buf
) / sizeof(buf
[0]);
1959 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1960 expect_eq_d(lstrlenW(buf
), size
);
1961 expect_eq_ws_i(buf
, module_name
);
1963 /* Buffer too small */
1964 size
= lstrlenW(module_name
)/2;
1965 lstrcpyW(buf
, deviceW
);
1966 SetLastError(0xdeadbeef);
1967 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1968 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1969 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1970 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
1972 /* Too small - not space for NUL terminator */
1973 size
= lstrlenW(module_name
);
1974 SetLastError(0xdeadbeef);
1975 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1976 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
1977 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1981 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
1982 expect_eq_d(0, size
);
1983 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1985 /* Buffer too small */
1986 size
= lstrlenW(module_name
)/2;
1987 SetLastError(0xdeadbeef);
1988 lstrcpyW(buf
, module_name
);
1989 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1990 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1991 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1992 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
1996 size
= sizeof(buf
) / sizeof(buf
[0]);
1997 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
1998 expect_eq_d(lstrlenW(buf
), size
);
1999 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
2000 ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
2002 module_name
[2] = '\0';
2004 size
= QueryDosDeviceW(module_name
, device
, sizeof(device
)/sizeof(device
[0]));
2005 ok(size
, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2006 len
= lstrlenW(device
);
2007 ok(size
>= len
+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size
, len
, wine_dbgstr_w(device
));
2009 if (size
>= lstrlenW(buf
))
2011 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2015 ok(buf
[len
] == '\\', "expected '%c' to be a '\\' in %s\n", buf
[len
], wine_dbgstr_w(module_name
));
2017 ok(lstrcmpiW(device
, buf
) == 0, "expected %s to match %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2018 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));
2024 static void test_Handles(void)
2026 HANDLE handle
= GetCurrentProcess();
2031 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
2032 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
2033 "invalid current process handle %p\n", handle
);
2034 ret
= GetExitCodeProcess( handle
, &code
);
2035 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
2037 /* truncated handle */
2038 SetLastError( 0xdeadbeef );
2039 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
2040 ret
= GetExitCodeProcess( handle
, &code
);
2041 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2042 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
2043 /* sign-extended handle */
2044 SetLastError( 0xdeadbeef );
2045 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
2046 ret
= GetExitCodeProcess( handle
, &code
);
2047 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
2048 /* invalid high-word */
2049 SetLastError( 0xdeadbeef );
2050 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
2051 ret
= GetExitCodeProcess( handle
, &code
);
2052 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2053 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
2056 handle
= GetStdHandle( STD_ERROR_HANDLE
);
2057 ok( handle
!= 0, "handle %p\n", handle
);
2058 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
2059 0, TRUE
, DUPLICATE_SAME_ACCESS
);
2060 SetStdHandle( STD_ERROR_HANDLE
, h3
);
2061 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
2062 h2
= GetStdHandle( STD_ERROR_HANDLE
);
2064 broken( h2
== h3
) || /* nt4, w2k */
2065 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
2066 "wrong handle %p/%p\n", h2
, h3
);
2067 SetStdHandle( STD_ERROR_HANDLE
, handle
);
2070 static void test_IsWow64Process(void)
2072 PROCESS_INFORMATION pi
;
2076 static char cmdline
[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2077 static char cmdline_wow64
[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2079 if (!pIsWow64Process
)
2081 skip("IsWow64Process is not available\n");
2085 memset(&si
, 0, sizeof(si
));
2087 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2088 si
.wShowWindow
= SW_HIDE
;
2089 ret
= CreateProcessA(NULL
, cmdline_wow64
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2092 trace("Created process %s\n", cmdline_wow64
);
2094 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2095 ok(ret
, "IsWow64Process failed.\n");
2096 ok(is_wow64
, "is_wow64 returned FALSE.\n");
2098 ret
= TerminateProcess(pi
.hProcess
, 0);
2099 ok(ret
, "TerminateProcess error\n");
2101 CloseHandle(pi
.hProcess
);
2102 CloseHandle(pi
.hThread
);
2105 memset(&si
, 0, sizeof(si
));
2107 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2108 si
.wShowWindow
= SW_HIDE
;
2109 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2112 trace("Created process %s\n", cmdline
);
2114 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2115 ok(ret
, "IsWow64Process failed.\n");
2116 ok(!is_wow64
, "is_wow64 returned TRUE.\n");
2118 ret
= TerminateProcess(pi
.hProcess
, 0);
2119 ok(ret
, "TerminateProcess error\n");
2121 CloseHandle(pi
.hProcess
);
2122 CloseHandle(pi
.hThread
);
2126 static void test_SystemInfo(void)
2128 SYSTEM_INFO si
, nsi
;
2131 if (!pGetNativeSystemInfo
)
2133 win_skip("GetNativeSystemInfo is not available\n");
2137 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
2140 pGetNativeSystemInfo(&nsi
);
2143 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
2145 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
2146 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2147 S(U(nsi
)).wProcessorArchitecture
);
2148 ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
,
2149 "Expected PROCESSOR_AMD_X8664, got %d\n",
2150 nsi
.dwProcessorType
);
2155 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
2156 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2157 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
2158 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
2159 "Expected no difference for dwProcessorType, got %d and %d\n",
2160 si
.dwProcessorType
, nsi
.dwProcessorType
);
2164 static void test_RegistryQuota(void)
2167 DWORD max_quota
, used_quota
;
2169 if (!pGetSystemRegistryQuota
)
2171 win_skip("GetSystemRegistryQuota is not available\n");
2175 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
2177 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2179 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
2181 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2183 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
2185 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2187 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
2189 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2192 static void test_TerminateProcess(void)
2194 static char cmdline
[] = "winver.exe";
2195 PROCESS_INFORMATION pi
;
2198 HANDLE dummy
, thread
;
2200 memset(&si
, 0, sizeof(si
));
2202 SetLastError(0xdeadbeef);
2203 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2204 ok(ret
, "CreateProcess error %u\n", GetLastError());
2206 SetLastError(0xdeadbeef);
2207 thread
= CreateRemoteThread(pi
.hProcess
, NULL
, 0, (void *)0xdeadbeef, NULL
, CREATE_SUSPENDED
, &ret
);
2208 ok(thread
!= 0, "CreateRemoteThread error %d\n", GetLastError());
2210 /* create a not closed thread handle duplicate in the target process */
2211 SetLastError(0xdeadbeef);
2212 ret
= DuplicateHandle(GetCurrentProcess(), thread
, pi
.hProcess
, &dummy
,
2213 0, FALSE
, DUPLICATE_SAME_ACCESS
);
2214 ok(ret
, "DuplicateHandle error %u\n", GetLastError());
2216 SetLastError(0xdeadbeef);
2217 ret
= TerminateThread(thread
, 0);
2218 ok(ret
, "TerminateThread error %u\n", GetLastError());
2219 CloseHandle(thread
);
2221 SetLastError(0xdeadbeef);
2222 ret
= TerminateProcess(pi
.hProcess
, 0);
2223 ok(ret
, "TerminateProcess error %u\n", GetLastError());
2225 CloseHandle(pi
.hProcess
);
2226 CloseHandle(pi
.hThread
);
2229 static void test_DuplicateHandle(void)
2231 char path
[MAX_PATH
], file_name
[MAX_PATH
];
2232 HANDLE f
, fmin
, out
;
2236 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2237 GetCurrentProcess(), &out
, 0, FALSE
,
2238 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2239 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2240 r
= GetHandleInformation(out
, &info
);
2241 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2242 ok(info
== 0, "info = %x\n", info
);
2243 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2246 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2247 GetCurrentProcess(), &out
, 0, TRUE
,
2248 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2249 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2250 r
= GetHandleInformation(out
, &info
);
2251 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2252 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2253 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2256 GetTempPathA(MAX_PATH
, path
);
2257 GetTempFileNameA(path
, "wt", 0, file_name
);
2258 f
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
2259 if (f
== INVALID_HANDLE_VALUE
)
2261 ok(0, "could not create %s\n", file_name
);
2265 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2266 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2267 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2268 ok(f
== out
, "f != out\n");
2269 r
= GetHandleInformation(out
, &info
);
2270 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2271 ok(info
== 0, "info = %x\n", info
);
2273 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2274 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2275 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2276 ok(f
== out
, "f != out\n");
2277 r
= GetHandleInformation(out
, &info
);
2278 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2279 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2281 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, HANDLE_FLAG_PROTECT_FROM_CLOSE
);
2282 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2283 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2284 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2285 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2286 ok(f
!= out
, "f == out\n");
2287 r
= GetHandleInformation(out
, &info
);
2288 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2289 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2290 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, 0);
2291 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2293 /* Test if DuplicateHandle allocates first free handle */
2304 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2305 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2306 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2307 ok(f
== out
, "f != out\n");
2309 DeleteFileA(file_name
);
2311 f
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2314 skip("DuplicateHandle on console handle\n");
2319 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2320 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2321 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2322 todo_wine
ok(f
!= out
, "f == out\n");
2326 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2327 static void _test_completion(int line
, HANDLE port
, DWORD ekey
, ULONG_PTR evalue
, ULONG_PTR eoverlapped
, DWORD wait
)
2329 LPOVERLAPPED overlapped
;
2334 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, wait
);
2336 ok_(__FILE__
, line
)(ret
, "GetQueuedCompletionStatus: %x\n", GetLastError());
2339 ok_(__FILE__
, line
)(key
== ekey
, "unexpected key %x\n", key
);
2340 ok_(__FILE__
, line
)(value
== evalue
, "unexpected value %p\n", (void *)value
);
2341 ok_(__FILE__
, line
)(overlapped
== (LPOVERLAPPED
)eoverlapped
, "unexpected overlapped %p\n", overlapped
);
2345 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2346 static void _create_process(int line
, const char *command
, LPPROCESS_INFORMATION pi
)
2349 char buffer
[MAX_PATH
];
2350 STARTUPINFOA si
= {0};
2352 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, command
);
2354 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, pi
);
2355 ok_(__FILE__
, line
)(ret
, "CreateProcess error %u\n", GetLastError());
2359 static void test_IsProcessInJob(void)
2362 PROCESS_INFORMATION pi
;
2366 if (!pIsProcessInJob
)
2368 win_skip("IsProcessInJob not available.\n");
2372 job
= pCreateJobObjectW(NULL
, NULL
);
2373 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2375 job2
= pCreateJobObjectW(NULL
, NULL
);
2376 ok(job2
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2378 create_process("wait", &pi
);
2381 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2382 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2383 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2386 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2387 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2388 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2391 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2392 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2393 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2395 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2396 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2399 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2400 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2401 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2404 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2405 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2406 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2409 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2410 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2411 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2413 TerminateProcess(pi
.hProcess
, 0);
2415 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2416 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2419 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2420 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2421 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2423 CloseHandle(pi
.hProcess
);
2424 CloseHandle(pi
.hThread
);
2429 static void test_TerminateJobObject(void)
2432 PROCESS_INFORMATION pi
;
2436 job
= pCreateJobObjectW(NULL
, NULL
);
2437 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2439 create_process("wait", &pi
);
2441 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2442 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2444 ret
= pTerminateJobObject(job
, 123);
2445 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2447 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2448 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2449 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2451 ret
= GetExitCodeProcess(pi
.hProcess
, &dwret
);
2452 ok(ret
, "GetExitCodeProcess error %u\n", GetLastError());
2453 ok(dwret
== 123 || broken(dwret
== 0) /* randomly fails on Win 2000 / XP */,
2454 "wrong exitcode %u\n", dwret
);
2456 CloseHandle(pi
.hProcess
);
2457 CloseHandle(pi
.hThread
);
2459 /* Test adding an already terminated process to a job object */
2460 create_process("exit", &pi
);
2462 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2463 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2465 SetLastError(0xdeadbeef);
2466 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2467 ok(!ret
, "AssignProcessToJobObject unexpectedly succeeded\n");
2468 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2470 CloseHandle(pi
.hProcess
);
2471 CloseHandle(pi
.hThread
);
2476 static void test_QueryInformationJobObject(void)
2478 char buf
[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST
) + sizeof(ULONG_PTR
) * 4];
2479 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2480 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info
;
2481 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit_info
= &ext_limit_info
.BasicLimitInformation
;
2482 DWORD dwret
, ret_len
;
2483 PROCESS_INFORMATION pi
[2];
2487 job
= pCreateJobObjectW(NULL
, NULL
);
2488 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2490 /* Only active processes are returned */
2491 create_process("exit", &pi
[0]);
2492 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2493 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2494 dwret
= WaitForSingleObject(pi
[0].hProcess
, 1000);
2495 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2497 CloseHandle(pi
[0].hProcess
);
2498 CloseHandle(pi
[0].hThread
);
2500 create_process("wait", &pi
[0]);
2501 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2502 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2504 create_process("wait", &pi
[1]);
2505 ret
= pAssignProcessToJobObject(job
, pi
[1].hProcess
);
2506 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2508 SetLastError(0xdeadbeef);
2509 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2510 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
), &ret_len
);
2511 ok(!ret
, "QueryInformationJobObject expected failure\n");
2513 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2515 SetLastError(0xdeadbeef);
2516 memset(buf
, 0, sizeof(buf
));
2517 pid_list
->NumberOfAssignedProcesses
= 42;
2518 pid_list
->NumberOfProcessIdsInList
= 42;
2519 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2520 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[1]), &ret_len
);
2521 ok(!ret
, "QueryInformationJobObject expected failure\n");
2523 expect_eq_d(ERROR_MORE_DATA
, GetLastError());
2526 expect_eq_d(42, pid_list
->NumberOfAssignedProcesses
);
2527 expect_eq_d(42, pid_list
->NumberOfProcessIdsInList
);
2530 memset(buf
, 0, sizeof(buf
));
2531 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2533 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2536 if (pid_list
->NumberOfAssignedProcesses
== 3) /* Win 8 */
2537 win_skip("Number of assigned processes broken on Win 8\n");
2540 ULONG_PTR
*list
= pid_list
->ProcessIdList
;
2542 ok(ret_len
== FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[2]),
2543 "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2545 expect_eq_d(2, pid_list
->NumberOfAssignedProcesses
);
2546 expect_eq_d(2, pid_list
->NumberOfProcessIdsInList
);
2547 expect_eq_d(pi
[0].dwProcessId
, list
[0]);
2548 expect_eq_d(pi
[1].dwProcessId
, list
[1]);
2552 /* test JobObjectBasicLimitInformation */
2553 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2554 sizeof(*basic_limit_info
) - 1, &ret_len
);
2555 ok(!ret
, "QueryInformationJobObject expected failure\n");
2556 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2558 ret_len
= 0xdeadbeef;
2559 memset(basic_limit_info
, 0x11, sizeof(*basic_limit_info
));
2560 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2561 sizeof(*basic_limit_info
), &ret_len
);
2562 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2563 ok(ret_len
== sizeof(*basic_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2564 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2566 /* test JobObjectExtendedLimitInformation */
2567 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2568 sizeof(ext_limit_info
) - 1, &ret_len
);
2569 ok(!ret
, "QueryInformationJobObject expected failure\n");
2570 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2572 ret_len
= 0xdeadbeef;
2573 memset(&ext_limit_info
, 0x11, sizeof(ext_limit_info
));
2574 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2575 sizeof(ext_limit_info
), &ret_len
);
2576 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2577 ok(ret_len
== sizeof(ext_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2578 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2580 TerminateProcess(pi
[0].hProcess
, 0);
2581 CloseHandle(pi
[0].hProcess
);
2582 CloseHandle(pi
[0].hThread
);
2584 TerminateProcess(pi
[1].hProcess
, 0);
2585 CloseHandle(pi
[1].hProcess
);
2586 CloseHandle(pi
[1].hThread
);
2591 static void test_CompletionPort(void)
2593 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
2594 PROCESS_INFORMATION pi
;
2599 job
= pCreateJobObjectW(NULL
, NULL
);
2600 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2602 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
2603 ok(port
!= NULL
, "CreateIoCompletionPort error %u\n", GetLastError());
2605 port_info
.CompletionKey
= job
;
2606 port_info
.CompletionPort
= port
;
2607 ret
= pSetInformationJobObject(job
, JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
2608 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2610 create_process("wait", &pi
);
2612 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2613 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2615 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2617 TerminateProcess(pi
.hProcess
, 0);
2618 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2619 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2621 test_completion(port
, JOB_OBJECT_MSG_EXIT_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2622 test_completion(port
, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
, (DWORD_PTR
)job
, 0, 100);
2624 CloseHandle(pi
.hProcess
);
2625 CloseHandle(pi
.hThread
);
2630 static void test_KillOnJobClose(void)
2632 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2633 PROCESS_INFORMATION pi
;
2638 job
= pCreateJobObjectW(NULL
, NULL
);
2639 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2641 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
;
2642 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2643 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
2645 win_skip("Kill on job close limit not available\n");
2648 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2650 create_process("wait", &pi
);
2652 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2653 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2657 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2658 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2659 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2661 CloseHandle(pi
.hProcess
);
2662 CloseHandle(pi
.hThread
);
2665 static void test_WaitForJobObject(void)
2668 PROCESS_INFORMATION pi
;
2672 /* test waiting for a job object when the process is killed */
2673 job
= pCreateJobObjectW(NULL
, NULL
);
2674 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2676 dwret
= WaitForSingleObject(job
, 100);
2677 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2679 create_process("wait", &pi
);
2681 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2682 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2684 dwret
= WaitForSingleObject(job
, 100);
2685 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2687 ret
= pTerminateJobObject(job
, 123);
2688 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2690 dwret
= WaitForSingleObject(job
, 500);
2691 ok(dwret
== WAIT_OBJECT_0
|| broken(dwret
== WAIT_TIMEOUT
),
2692 "WaitForSingleObject returned %u\n", dwret
);
2694 if (dwret
== WAIT_TIMEOUT
) /* Win 2000/XP */
2696 CloseHandle(pi
.hProcess
);
2697 CloseHandle(pi
.hThread
);
2699 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2703 /* the object is not reset immediately */
2704 dwret
= WaitForSingleObject(job
, 100);
2705 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2707 CloseHandle(pi
.hProcess
);
2708 CloseHandle(pi
.hThread
);
2710 /* creating a new process doesn't reset the signalled state */
2711 create_process("wait", &pi
);
2713 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2714 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2716 dwret
= WaitForSingleObject(job
, 100);
2717 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2719 ret
= pTerminateJobObject(job
, 123);
2720 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2722 CloseHandle(pi
.hProcess
);
2723 CloseHandle(pi
.hThread
);
2727 /* repeat the test, but this time the process terminates properly */
2728 job
= pCreateJobObjectW(NULL
, NULL
);
2729 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2731 dwret
= WaitForSingleObject(job
, 100);
2732 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2734 create_process("exit", &pi
);
2736 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2737 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2739 dwret
= WaitForSingleObject(job
, 100);
2740 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2742 CloseHandle(pi
.hProcess
);
2743 CloseHandle(pi
.hThread
);
2747 static HANDLE
test_AddSelfToJob(void)
2752 job
= pCreateJobObjectW(NULL
, NULL
);
2753 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2755 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
2756 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2761 static void test_jobInheritance(HANDLE job
)
2763 char buffer
[MAX_PATH
];
2764 PROCESS_INFORMATION pi
;
2765 STARTUPINFOA si
= {0};
2769 if (!pIsProcessInJob
)
2771 win_skip("IsProcessInJob not available.\n");
2775 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2777 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2778 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2781 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2782 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2783 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2785 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2786 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2788 CloseHandle(pi
.hProcess
);
2789 CloseHandle(pi
.hThread
);
2792 static void test_BreakawayOk(HANDLE job
)
2794 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2795 PROCESS_INFORMATION pi
;
2796 STARTUPINFOA si
= {0};
2797 char buffer
[MAX_PATH
];
2801 if (!pIsProcessInJob
)
2803 win_skip("IsProcessInJob not available.\n");
2807 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2809 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2810 ok(!ret
, "CreateProcessA expected failure\n");
2811 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2815 TerminateProcess(pi
.hProcess
, 0);
2817 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2818 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2820 CloseHandle(pi
.hProcess
);
2821 CloseHandle(pi
.hThread
);
2824 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
2825 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2826 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2828 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2829 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2831 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2832 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2833 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2835 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2836 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2838 CloseHandle(pi
.hProcess
);
2839 CloseHandle(pi
.hThread
);
2841 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
2842 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2843 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2845 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2846 ok(ret
, "CreateProcess error %u\n", GetLastError());
2848 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2849 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2850 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2852 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2853 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2855 CloseHandle(pi
.hProcess
);
2856 CloseHandle(pi
.hThread
);
2858 /* unset breakaway ok */
2859 limit_info
.BasicLimitInformation
.LimitFlags
= 0;
2860 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2861 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2864 static void test_StartupNoConsole(void)
2867 char buffer
[MAX_PATH
];
2868 STARTUPINFOA startup
;
2869 PROCESS_INFORMATION info
;
2871 memset(&startup
, 0, sizeof(startup
));
2872 startup
.cb
= sizeof(startup
);
2873 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
2874 startup
.wShowWindow
= SW_SHOWNORMAL
;
2875 get_file_name(resfile
);
2876 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
2877 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
2878 &info
), "CreateProcess\n");
2879 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
2880 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
2881 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
2882 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
2883 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
2884 okChildInt("TEB", "hStdInput", 0);
2885 okChildInt("TEB", "hStdOutput", 0);
2886 okChildInt("TEB", "hStdError", 0);
2888 DeleteFileA(resfile
);
2892 static void test_GetNumaProcessorNode(void)
2899 if (!pGetNumaProcessorNode
)
2901 win_skip("GetNumaProcessorNode is missing\n");
2906 for (i
= 0; i
< 256; i
++)
2908 SetLastError(0xdeadbeef);
2909 node
= (i
< si
.dwNumberOfProcessors
) ? 0xFF : 0xAA;
2910 ret
= pGetNumaProcessorNode(i
, &node
);
2911 if (i
< si
.dwNumberOfProcessors
)
2913 ok(ret
, "GetNumaProcessorNode returned FALSE for processor %d\n", i
);
2914 ok(node
!= 0xFF, "expected node != 0xFF, but got 0xFF\n");
2918 ok(!ret
, "GetNumaProcessorNode returned TRUE for processor %d\n", i
);
2919 ok(node
== 0xFF || broken(node
== 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node
);
2920 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2925 static void test_session_info(void)
2927 DWORD session_id
, active_session
;
2930 if (!pProcessIdToSessionId
)
2932 win_skip("ProcessIdToSessionId is missing\n");
2936 r
= pProcessIdToSessionId(GetCurrentProcessId(), &session_id
);
2937 ok(r
, "ProcessIdToSessionId failed: %u\n", GetLastError());
2938 trace("session_id = %x\n", session_id
);
2940 active_session
= pWTSGetActiveConsoleSessionId();
2941 trace("active_session = %x\n", active_session
);
2944 static void test_process_info(void)
2947 static const ULONG info_size
[] =
2949 sizeof(PROCESS_BASIC_INFORMATION
) /* ProcessBasicInformation */,
2950 sizeof(QUOTA_LIMITS
) /* ProcessQuotaLimits */,
2951 sizeof(IO_COUNTERS
) /* ProcessIoCounters */,
2952 sizeof(VM_COUNTERS
) /* ProcessVmCounters */,
2953 sizeof(KERNEL_USER_TIMES
) /* ProcessTimes */,
2954 sizeof(ULONG
) /* ProcessBasePriority */,
2955 sizeof(ULONG
) /* ProcessRaisePriority */,
2956 sizeof(HANDLE
) /* ProcessDebugPort */,
2957 sizeof(HANDLE
) /* ProcessExceptionPort */,
2958 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
2959 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
2960 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
2961 sizeof(ULONG
) /* ProcessDefaultHardErrorMode */,
2962 0 /* ProcessIoPortHandlers: kernel-mode only */,
2963 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
2964 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
2965 sizeof(ULONG
) /* ProcessUserModeIOPL */,
2966 sizeof(BOOLEAN
) /* ProcessEnableAlignmentFaultFixup */,
2967 sizeof(PROCESS_PRIORITY_CLASS
) /* ProcessPriorityClass */,
2968 sizeof(ULONG
) /* ProcessWx86Information */,
2969 sizeof(ULONG
) /* ProcessHandleCount */,
2970 sizeof(ULONG_PTR
) /* ProcessAffinityMask */,
2971 sizeof(ULONG
) /* ProcessPriorityBoost */,
2972 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
2973 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
2974 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
2975 sizeof(ULONG_PTR
) /* ProcessWow64Information */,
2976 sizeof(buf
) /* ProcessImageFileName */,
2977 sizeof(ULONG
) /* ProcessLUIDDeviceMapsEnabled */,
2978 sizeof(ULONG
) /* ProcessBreakOnTermination */,
2979 sizeof(HANDLE
) /* ProcessDebugObjectHandle */,
2980 sizeof(ULONG
) /* ProcessDebugFlags */,
2981 sizeof(buf
) /* ProcessHandleTracing */,
2982 sizeof(ULONG
) /* ProcessIoPriority */,
2983 sizeof(ULONG
) /* ProcessExecuteFlags */,
2984 #if 0 /* FIXME: Add remaining classes */
2985 ProcessResourceManagement
,
2986 sizeof(ULONG
) /* ProcessCookie */,
2987 sizeof(SECTION_IMAGE_INFORMATION
) /* ProcessImageInformation */,
2988 sizeof(PROCESS_CYCLE_TIME_INFORMATION
) /* ProcessCycleTime */,
2989 sizeof(ULONG
) /* ProcessPagePriority */,
2990 40 /* ProcessInstrumentationCallback */,
2991 sizeof(PROCESS_STACK_ALLOCATION_INFORMATION
) /* ProcessThreadStackAllocation */,
2992 sizeof(PROCESS_WS_WATCH_INFORMATION_EX
[]) /* ProcessWorkingSetWatchEx */,
2993 sizeof(buf
) /* ProcessImageFileNameWin32 */,
2994 sizeof(HANDLE
) /* ProcessImageFileMapping */,
2995 sizeof(PROCESS_AFFINITY_UPDATE_MODE
) /* ProcessAffinityUpdateMode */,
2996 sizeof(PROCESS_MEMORY_ALLOCATION_MODE
) /* ProcessMemoryAllocationMode */,
2997 sizeof(USHORT
[]) /* ProcessGroupInformation */,
2998 sizeof(ULONG
) /* ProcessTokenVirtualizationEnabled */,
2999 sizeof(ULONG_PTR
) /* ProcessConsoleHostProcess */,
3000 sizeof(PROCESS_WINDOW_INFORMATION
) /* ProcessWindowInformation */,
3001 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION
) /* ProcessHandleInformation */,
3002 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION
) /* ProcessMitigationPolicy */,
3003 sizeof(ProcessDynamicFunctionTableInformation
) /* ProcessDynamicFunctionTableInformation */,
3004 sizeof(?) /* ProcessHandleCheckingMode */,
3005 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION
) /* ProcessKeepAliveCount */,
3006 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION
) /* ProcessRevokeFileHandles */,
3007 sizeof(PROCESS_WORKING_SET_CONTROL
) /* ProcessWorkingSetControl */,
3008 sizeof(?) /* ProcessHandleTable */,
3009 sizeof(?) /* ProcessCheckStackExtentsMode */,
3010 sizeof(buf
) /* ProcessCommandLineInformation */,
3011 sizeof(PS_PROTECTION
) /* ProcessProtectionInformation */,
3012 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO
) /* ProcessMemoryExhaustion */,
3013 sizeof(PROCESS_FAULT_INFORMATION
) /* ProcessFaultInformation */,
3014 sizeof(PROCESS_TELEMETRY_ID_INFORMATION
) /* ProcessTelemetryIdInformation */,
3015 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION
) /* ProcessCommitReleaseInformation */,
3016 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3017 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3018 0 /* ProcessReserved1Information */,
3019 0 /* ProcessReserved2Information */,
3020 sizeof(?) /* ProcessSubsystemProcess */,
3021 sizeof(PROCESS_JOB_MEMORY_INFO
) /* ProcessJobMemoryInformation */,
3025 ULONG i
, status
, ret_len
, size
;
3027 if (!pNtQueryInformationProcess
)
3029 win_skip("NtQueryInformationProcess is not available on this platform\n");
3033 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
3036 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
3040 for (i
= 0; i
< MaxProcessInfoClass
; i
++)
3042 size
= info_size
[i
];
3043 if (!size
) size
= sizeof(buf
);
3045 status
= pNtQueryInformationProcess(hproc
, i
, buf
, info_size
[i
], &ret_len
);
3046 if (status
== STATUS_NOT_IMPLEMENTED
) continue;
3047 if (status
== STATUS_INVALID_INFO_CLASS
) continue;
3048 if (status
== STATUS_INFO_LENGTH_MISMATCH
) continue;
3052 case ProcessBasicInformation
:
3053 case ProcessQuotaLimits
:
3055 case ProcessPriorityClass
:
3056 case ProcessPriorityBoost
:
3057 case ProcessLUIDDeviceMapsEnabled
:
3058 case 33 /* ProcessIoPriority */:
3059 case ProcessIoCounters
:
3060 case ProcessVmCounters
:
3061 case ProcessWow64Information
:
3062 case ProcessDefaultHardErrorMode
:
3063 case ProcessHandleCount
:
3064 ok(status
== STATUS_SUCCESS
, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3067 case ProcessImageFileName
:
3069 ok(status
== STATUS_SUCCESS
, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3072 case ProcessAffinityMask
:
3073 case ProcessBreakOnTermination
:
3074 ok(status
== STATUS_ACCESS_DENIED
/* before win8 */ || status
== STATUS_SUCCESS
/* win8 is less strict */,
3075 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3078 case ProcessDebugObjectHandle
:
3079 ok(status
== STATUS_ACCESS_DENIED
|| status
== STATUS_PORT_NOT_SET
,
3080 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3083 case ProcessExecuteFlags
:
3084 case ProcessDebugPort
:
3085 case ProcessDebugFlags
:
3087 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3091 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3099 static void test_GetLogicalProcessorInformationEx(void)
3101 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*info
;
3105 if (!pGetLogicalProcessorInformationEx
)
3107 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3111 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, NULL
);
3112 ok(!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "got %d, error %d\n", ret
, GetLastError());
3115 ret
= pGetLogicalProcessorInformationEx(RelationProcessorCore
, NULL
, &len
);
3116 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %d\n", ret
, GetLastError());
3117 ok(len
> 0, "got %u\n", len
);
3120 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, &len
);
3121 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %d\n", ret
, GetLastError());
3122 ok(len
> 0, "got %u\n", len
);
3124 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
3125 ret
= pGetLogicalProcessorInformationEx(RelationAll
, info
, &len
);
3126 ok(ret
, "got %d, error %d\n", ret
, GetLastError());
3127 ok(info
->Size
> 0, "got %u\n", info
->Size
);
3128 HeapFree(GetProcessHeap(), 0, info
);
3131 static void test_largepages(void)
3135 if (!pGetLargePageMinimum
) {
3136 skip("No GetLargePageMinimum support.\n");
3139 size
= pGetLargePageMinimum();
3141 ok((size
== 0) || (size
== 2*1024*1024) || (size
== 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size
);
3148 ok(b
, "Basic init of CreateProcess test\n");
3153 if (!strcmp(myARGV
[2], "dump") && myARGC
>= 4)
3155 doChild(myARGV
[3], (myARGC
>= 5) ? myARGV
[4] : NULL
);
3158 else if (!strcmp(myARGV
[2], "wait"))
3161 ok(0, "Child process not killed\n");
3164 else if (!strcmp(myARGV
[2], "exit"))
3169 else if (!strcmp(myARGV
[2], "nested") && myARGC
>= 4)
3171 char buffer
[MAX_PATH
];
3172 STARTUPINFOA startup
;
3173 PROCESS_INFORMATION info
;
3175 memset(&startup
, 0, sizeof(startup
));
3176 startup
.cb
= sizeof(startup
);
3177 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3178 startup
.wShowWindow
= SW_SHOWNORMAL
;
3180 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, myARGV
[3]);
3181 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
3182 CloseHandle(info
.hProcess
);
3183 CloseHandle(info
.hThread
);
3187 ok(0, "Unexpected command %s\n", myARGV
[2]);
3191 test_process_info();
3192 test_TerminateProcess();
3199 test_DebuggingFlag();
3203 test_GetProcessVersion();
3204 test_GetProcessImageFileNameA();
3205 test_QueryFullProcessImageNameA();
3206 test_QueryFullProcessImageNameW();
3208 test_IsWow64Process();
3210 test_RegistryQuota();
3211 test_DuplicateHandle();
3212 test_StartupNoConsole();
3213 test_GetNumaProcessorNode();
3214 test_session_info();
3215 test_GetLogicalProcessorInformationEx();
3218 /* things that can be tested:
3219 * lookup: check the way program to be executed is searched
3220 * handles: check the handle inheritance stuff (+sec options)
3221 * console: check if console creation parameters work
3224 if (!pCreateJobObjectW
)
3226 win_skip("No job object support\n");
3230 test_IsProcessInJob();
3231 test_TerminateJobObject();
3232 test_QueryInformationJobObject();
3233 test_CompletionPort();
3234 test_KillOnJobClose();
3235 test_WaitForJobObject();
3236 job
= test_AddSelfToJob();
3237 test_jobInheritance(job
);
3238 test_BreakawayOk(job
);