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);
91 static BOOL (WINAPI
*pInitializeProcThreadAttributeList
)(struct _PROC_THREAD_ATTRIBUTE_LIST
*, DWORD
, DWORD
, SIZE_T
*);
92 static BOOL (WINAPI
*pUpdateProcThreadAttribute
)(struct _PROC_THREAD_ATTRIBUTE_LIST
*, DWORD
, DWORD_PTR
, void *,SIZE_T
,void*,SIZE_T
*);
93 static void (WINAPI
*pDeleteProcThreadAttributeList
)(struct _PROC_THREAD_ATTRIBUTE_LIST
*);
94 static DWORD (WINAPI
*pGetActiveProcessorCount
)(WORD
);
96 /* ############################### */
97 static char base
[MAX_PATH
];
98 static char selfname
[MAX_PATH
];
100 static char resfile
[MAX_PATH
];
103 static char** myARGV
;
105 /* As some environment variables get very long on Unix, we only test for
106 * the first 127 bytes.
107 * Note that increasing this value past 256 may exceed the buffer size
108 * limitations of the *Profile functions (at least on Wine).
110 #define MAX_LISTED_ENV_VAR 128
112 /* ---------------- portable memory allocation thingie */
114 static char memory
[1024*256];
115 static char* memory_index
= memory
;
117 static char* grab_memory(size_t len
)
119 char* ret
= memory_index
;
121 len
= (len
+ 3) & ~3;
123 assert(memory_index
<= memory
+ sizeof(memory
));
127 static void release_memory(void)
129 memory_index
= memory
;
132 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
134 static const char* encodeA(const char* str
)
140 len
= strlen(str
) + 1;
141 ptr
= grab_memory(len
* 2 + 1);
142 for (i
= 0; i
< len
; i
++)
143 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
148 static const char* encodeW(const WCHAR
* str
)
154 len
= lstrlenW(str
) + 1;
155 ptr
= grab_memory(len
* 4 + 1);
157 for (i
= 0; i
< len
; i
++)
158 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
163 static unsigned decode_char(char c
)
165 if (c
>= '0' && c
<= '9') return c
- '0';
166 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
167 assert(c
>= 'A' && c
<= 'F');
171 static char* decodeA(const char* str
)
176 len
= strlen(str
) / 2;
177 if (!len
--) return NULL
;
178 ptr
= grab_memory(len
+ 1);
179 for (i
= 0; i
< len
; i
++)
180 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
185 /* This will be needed to decode Unicode strings saved by the child process
186 * when we test Unicode functions.
188 static WCHAR
* decodeW(const char* str
)
194 len
= strlen(str
) / 4;
195 if (!len
--) return NULL
;
196 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
197 for (i
= 0; i
< len
; i
++)
198 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
199 (decode_char(str
[4 * i
+ 1]) << 8) |
200 (decode_char(str
[4 * i
+ 2]) << 4) |
201 (decode_char(str
[4 * i
+ 3]) << 0);
206 /******************************************************************
209 * generates basic information like:
210 * base: absolute path to curr dir
211 * selfname: the way to reinvoke ourselves
212 * exename: executable without the path
213 * function-pointers, which are not implemented in all windows versions
215 static BOOL
init(void)
219 myARGC
= winetest_get_mainargs( &myARGV
);
220 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return FALSE
;
221 strcpy(selfname
, myARGV
[0]);
223 /* Strip the path of selfname */
224 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
225 else exename
= selfname
;
227 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
229 hkernel32
= GetModuleHandleA("kernel32");
230 hntdll
= GetModuleHandleA("ntdll.dll");
232 pNtQueryInformationProcess
= (void *)GetProcAddress(hntdll
, "NtQueryInformationProcess");
234 pGetNativeSystemInfo
= (void *) GetProcAddress(hkernel32
, "GetNativeSystemInfo");
235 pGetSystemRegistryQuota
= (void *) GetProcAddress(hkernel32
, "GetSystemRegistryQuota");
236 pIsWow64Process
= (void *) GetProcAddress(hkernel32
, "IsWow64Process");
237 pVirtualAllocEx
= (void *) GetProcAddress(hkernel32
, "VirtualAllocEx");
238 pVirtualFreeEx
= (void *) GetProcAddress(hkernel32
, "VirtualFreeEx");
239 pQueryFullProcessImageNameA
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameA");
240 pQueryFullProcessImageNameW
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameW");
241 pK32GetProcessImageFileNameA
= (void *) GetProcAddress(hkernel32
, "K32GetProcessImageFileNameA");
242 pCreateJobObjectW
= (void *)GetProcAddress(hkernel32
, "CreateJobObjectW");
243 pAssignProcessToJobObject
= (void *)GetProcAddress(hkernel32
, "AssignProcessToJobObject");
244 pIsProcessInJob
= (void *)GetProcAddress(hkernel32
, "IsProcessInJob");
245 pTerminateJobObject
= (void *)GetProcAddress(hkernel32
, "TerminateJobObject");
246 pQueryInformationJobObject
= (void *)GetProcAddress(hkernel32
, "QueryInformationJobObject");
247 pSetInformationJobObject
= (void *)GetProcAddress(hkernel32
, "SetInformationJobObject");
248 pCreateIoCompletionPort
= (void *)GetProcAddress(hkernel32
, "CreateIoCompletionPort");
249 pGetNumaProcessorNode
= (void *)GetProcAddress(hkernel32
, "GetNumaProcessorNode");
250 pProcessIdToSessionId
= (void *)GetProcAddress(hkernel32
, "ProcessIdToSessionId");
251 pWTSGetActiveConsoleSessionId
= (void *)GetProcAddress(hkernel32
, "WTSGetActiveConsoleSessionId");
252 pCreateToolhelp32Snapshot
= (void *)GetProcAddress(hkernel32
, "CreateToolhelp32Snapshot");
253 pProcess32First
= (void *)GetProcAddress(hkernel32
, "Process32First");
254 pProcess32Next
= (void *)GetProcAddress(hkernel32
, "Process32Next");
255 pThread32First
= (void *)GetProcAddress(hkernel32
, "Thread32First");
256 pThread32Next
= (void *)GetProcAddress(hkernel32
, "Thread32Next");
257 pGetLogicalProcessorInformationEx
= (void *)GetProcAddress(hkernel32
, "GetLogicalProcessorInformationEx");
258 pGetLargePageMinimum
= (void *)GetProcAddress(hkernel32
, "GetLargePageMinimum");
259 pInitializeProcThreadAttributeList
= (void *)GetProcAddress(hkernel32
, "InitializeProcThreadAttributeList");
260 pUpdateProcThreadAttribute
= (void *)GetProcAddress(hkernel32
, "UpdateProcThreadAttribute");
261 pDeleteProcThreadAttributeList
= (void *)GetProcAddress(hkernel32
, "DeleteProcThreadAttributeList");
262 pGetActiveProcessorCount
= (void *)GetProcAddress(hkernel32
, "GetActiveProcessorCount");
267 /******************************************************************
270 * generates an absolute file_name for temporary file
273 static void get_file_name(char* buf
)
278 GetTempPathA(sizeof(path
), path
);
279 GetTempFileNameA(path
, "wt", 0, buf
);
282 /******************************************************************
283 * static void childPrintf
286 static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h
, const char* fmt
, ...)
289 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
292 va_start(valist
, fmt
);
293 vsprintf(buffer
, fmt
, valist
);
295 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
299 /******************************************************************
302 * output most of the information in the child process
304 static void doChild(const char* file
, const char* option
)
306 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
310 char *ptrA
, *ptrA_save
;
311 WCHAR
*ptrW
, *ptrW_save
;
313 WCHAR bufW
[MAX_PATH
];
314 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
319 if (hFile
== INVALID_HANDLE_VALUE
) return;
321 /* output of startup info (Ansi) */
322 GetStartupInfoA(&siA
);
324 "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
325 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
326 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
327 "dwFlags=%u\nwShowWindow=%u\n"
328 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
329 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
330 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
331 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
332 siA
.dwFlags
, siA
.wShowWindow
,
333 (DWORD_PTR
)siA
.hStdInput
, (DWORD_PTR
)siA
.hStdOutput
, (DWORD_PTR
)siA
.hStdError
);
335 /* check the console handles in the TEB */
336 childPrintf(hFile
, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
337 (DWORD_PTR
)params
->hStdInput
, (DWORD_PTR
)params
->hStdOutput
,
338 (DWORD_PTR
)params
->hStdError
);
340 /* since GetStartupInfoW is only implemented in win2k,
341 * zero out before calling so we can notice the difference
343 memset(&siW
, 0, sizeof(siW
));
344 GetStartupInfoW(&siW
);
346 "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
347 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
348 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
349 "dwFlags=%u\nwShowWindow=%u\n"
350 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
351 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
352 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
353 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
354 siW
.dwFlags
, siW
.wShowWindow
,
355 (DWORD_PTR
)siW
.hStdInput
, (DWORD_PTR
)siW
.hStdOutput
, (DWORD_PTR
)siW
.hStdError
);
358 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
359 for (i
= 0; i
< myARGC
; i
++)
361 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
363 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
364 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
366 /* output toolhelp information */
367 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
368 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
369 memset(&pe
, 0, sizeof(pe
));
370 pe
.dwSize
= sizeof(pe
);
371 if (pProcess32First(snapshot
, &pe
))
373 while (pe
.th32ProcessID
!= GetCurrentProcessId())
374 if (!pProcess32Next(snapshot
, &pe
)) break;
376 CloseHandle(snapshot
);
377 ok(pe
.th32ProcessID
== GetCurrentProcessId(), "failed to find current process in snapshot\n");
379 "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n"
380 "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n"
381 "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n",
382 pe
.cntUsage
, pe
.th32DefaultHeapID
, pe
.th32ModuleID
,
383 pe
.cntThreads
, pe
.th32ParentProcessID
, pe
.pcPriClassBase
,
384 pe
.dwFlags
, encodeA(pe
.szExeFile
));
386 /* output of environment (Ansi) */
387 ptrA_save
= ptrA
= GetEnvironmentStringsA();
390 char env_var
[MAX_LISTED_ENV_VAR
];
392 childPrintf(hFile
, "[EnvironmentA]\n");
396 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
397 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
399 ptrA
+= strlen(ptrA
) + 1;
401 childPrintf(hFile
, "len=%d\n\n", i
);
402 FreeEnvironmentStringsA(ptrA_save
);
405 /* output of environment (Unicode) */
406 ptrW_save
= ptrW
= GetEnvironmentStringsW();
409 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
411 childPrintf(hFile
, "[EnvironmentW]\n");
415 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
416 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
417 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
419 ptrW
+= lstrlenW(ptrW
) + 1;
421 childPrintf(hFile
, "len=%d\n\n", i
);
422 FreeEnvironmentStringsW(ptrW_save
);
425 childPrintf(hFile
, "[Misc]\n");
426 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
427 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
428 if (GetCurrentDirectoryW(sizeof(bufW
) / sizeof(bufW
[0]), bufW
))
429 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
430 childPrintf(hFile
, "\n");
432 if (option
&& strcmp(option
, "console") == 0)
434 CONSOLE_SCREEN_BUFFER_INFO sbi
;
435 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
436 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
437 DWORD modeIn
, modeOut
;
439 childPrintf(hFile
, "[Console]\n");
440 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
442 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
443 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
444 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
445 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
446 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
447 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
449 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
450 GetConsoleCP(), GetConsoleOutputCP());
451 if (GetConsoleMode(hConIn
, &modeIn
))
452 childPrintf(hFile
, "InputMode=%u\n", modeIn
);
453 if (GetConsoleMode(hConOut
, &modeOut
))
454 childPrintf(hFile
, "OutputMode=%u\n", modeOut
);
456 /* now that we have written all relevant information, let's change it */
457 SetLastError(0xdeadbeef);
458 ret
= SetConsoleCP(1252);
459 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
461 win_skip("Setting the codepage is not implemented\n");
465 ok(ret
, "Setting CP\n");
466 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
469 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
470 ok( ret
, "Setting mode (%d)\n", GetLastError());
471 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
472 ok( ret
, "Setting mode (%d)\n", GetLastError());
473 sbi
.dwCursorPosition
.X
^= 1;
474 sbi
.dwCursorPosition
.Y
^= 1;
475 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
476 ok( ret
, "Setting cursor position (%d)\n", GetLastError());
478 if (option
&& strcmp(option
, "stdhandle") == 0)
480 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
481 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
483 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
488 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
489 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
490 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
494 if (option
&& strcmp(option
, "exit_code") == 0)
496 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
504 static char* getChildString(const char* sect
, const char* key
)
506 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
509 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
510 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
511 assert(!(strlen(buf
) & 1));
516 static WCHAR
* getChildStringW(const char* sect
, const char* key
)
518 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
521 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
522 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
523 assert(!(strlen(buf
) & 1));
528 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
529 * others... (windows uses stricmp while Un*x uses strcasecmp...)
531 static int wtstrcasecmp(const char* p1
, const char* p2
)
536 while (c1
== c2
&& c1
)
538 c1
= *p1
++; c2
= *p2
++;
541 c1
= toupper(c1
); c2
= toupper(c2
);
547 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
549 if (!s1
&& !s2
) return 0;
552 return (sensitive
) ? strcmp(s1
, s2
) : wtstrcasecmp(s1
, s2
);
555 static void ok_child_string( int line
, const char *sect
, const char *key
,
556 const char *expect
, int sensitive
)
558 char* result
= getChildString( sect
, key
);
559 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
560 sect
, key
, expect
? expect
: "(null)", result
);
563 static void ok_child_stringWA( int line
, const char *sect
, const char *key
,
564 const char *expect
, int sensitive
)
569 WCHAR
* result
= getChildStringW( sect
, key
);
571 len
= MultiByteToWideChar( CP_ACP
, 0, expect
, -1, NULL
, 0);
572 expectW
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
573 MultiByteToWideChar( CP_ACP
, 0, expect
, -1, expectW
, len
);
575 len
= WideCharToMultiByte( CP_ACP
, 0, result
, -1, NULL
, 0, NULL
, NULL
);
576 resultA
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(CHAR
));
577 WideCharToMultiByte( CP_ACP
, 0, result
, -1, resultA
, len
, NULL
, NULL
);
580 ok_(__FILE__
, line
)( lstrcmpW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
581 sect
, key
, expect
? expect
: "(null)", resultA
);
583 ok_(__FILE__
, line
)( lstrcmpiW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
584 sect
, key
, expect
? expect
: "(null)", resultA
);
585 HeapFree(GetProcessHeap(),0,expectW
);
586 HeapFree(GetProcessHeap(),0,resultA
);
589 static void ok_child_int( int line
, const char *sect
, const char *key
, UINT expect
)
591 UINT result
= GetPrivateProfileIntA( sect
, key
, !expect
, resfile
);
592 ok_(__FILE__
, line
)( result
== expect
, "%s:%s expected %u, but got %u\n", sect
, key
, expect
, result
);
595 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
596 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
597 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
598 #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
600 static void test_Startup(void)
602 char buffer
[MAX_PATH
];
603 PROCESS_INFORMATION info
;
604 STARTUPINFOA startup
,si
;
606 static CHAR title
[] = "I'm the title string",
607 desktop
[] = "winsta0\\default",
610 /* let's start simplistic */
611 memset(&startup
, 0, sizeof(startup
));
612 startup
.cb
= sizeof(startup
);
613 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
614 startup
.wShowWindow
= SW_SHOWNORMAL
;
616 get_file_name(resfile
);
617 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
618 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
619 /* wait for child to terminate */
620 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
621 /* child process has changed result file, so let profile functions know about it */
622 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
624 GetStartupInfoA(&si
);
625 okChildInt("StartupInfoA", "cb", startup
.cb
);
626 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
627 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
628 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
629 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
630 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
631 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
632 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
633 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
634 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
635 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
637 DeleteFileA(resfile
);
639 /* not so simplistic now */
640 memset(&startup
, 0, sizeof(startup
));
641 startup
.cb
= sizeof(startup
);
642 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
643 startup
.wShowWindow
= SW_SHOWNORMAL
;
644 startup
.lpTitle
= title
;
645 startup
.lpDesktop
= desktop
;
646 startup
.dwXCountChars
= 0x12121212;
647 startup
.dwYCountChars
= 0x23232323;
648 startup
.dwX
= 0x34343434;
649 startup
.dwY
= 0x45454545;
650 startup
.dwXSize
= 0x56565656;
651 startup
.dwYSize
= 0x67676767;
652 startup
.dwFillAttribute
= 0xA55A;
654 get_file_name(resfile
);
655 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
656 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
657 /* wait for child to terminate */
658 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
659 /* child process has changed result file, so let profile functions know about it */
660 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
662 okChildInt("StartupInfoA", "cb", startup
.cb
);
663 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
664 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
665 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
666 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
667 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
668 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
669 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
670 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
671 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
672 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
673 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
675 DeleteFileA(resfile
);
677 /* not so simplistic now */
678 memset(&startup
, 0, sizeof(startup
));
679 startup
.cb
= sizeof(startup
);
680 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
681 startup
.wShowWindow
= SW_SHOWNORMAL
;
682 startup
.lpTitle
= title
;
683 startup
.lpDesktop
= NULL
;
684 startup
.dwXCountChars
= 0x12121212;
685 startup
.dwYCountChars
= 0x23232323;
686 startup
.dwX
= 0x34343434;
687 startup
.dwY
= 0x45454545;
688 startup
.dwXSize
= 0x56565656;
689 startup
.dwYSize
= 0x67676767;
690 startup
.dwFillAttribute
= 0xA55A;
692 get_file_name(resfile
);
693 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
694 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
695 /* wait for child to terminate */
696 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
697 /* child process has changed result file, so let profile functions know about it */
698 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
700 okChildInt("StartupInfoA", "cb", startup
.cb
);
701 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
702 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
703 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
704 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
705 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
706 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
707 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
708 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
709 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
710 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
711 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
713 DeleteFileA(resfile
);
715 /* not so simplistic now */
716 memset(&startup
, 0, sizeof(startup
));
717 startup
.cb
= sizeof(startup
);
718 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
719 startup
.wShowWindow
= SW_SHOWNORMAL
;
720 startup
.lpTitle
= title
;
721 startup
.lpDesktop
= empty
;
722 startup
.dwXCountChars
= 0x12121212;
723 startup
.dwYCountChars
= 0x23232323;
724 startup
.dwX
= 0x34343434;
725 startup
.dwY
= 0x45454545;
726 startup
.dwXSize
= 0x56565656;
727 startup
.dwYSize
= 0x67676767;
728 startup
.dwFillAttribute
= 0xA55A;
730 get_file_name(resfile
);
731 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
732 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
733 /* wait for child to terminate */
734 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
735 /* child process has changed result file, so let profile functions know about it */
736 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
738 okChildInt("StartupInfoA", "cb", startup
.cb
);
739 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
740 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
741 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
742 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
743 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
744 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
745 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
746 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
747 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
748 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
749 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
751 DeleteFileA(resfile
);
753 /* not so simplistic now */
754 memset(&startup
, 0, sizeof(startup
));
755 startup
.cb
= sizeof(startup
);
756 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
757 startup
.wShowWindow
= SW_SHOWNORMAL
;
758 startup
.lpTitle
= NULL
;
759 startup
.lpDesktop
= desktop
;
760 startup
.dwXCountChars
= 0x12121212;
761 startup
.dwYCountChars
= 0x23232323;
762 startup
.dwX
= 0x34343434;
763 startup
.dwY
= 0x45454545;
764 startup
.dwXSize
= 0x56565656;
765 startup
.dwYSize
= 0x67676767;
766 startup
.dwFillAttribute
= 0xA55A;
768 get_file_name(resfile
);
769 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
770 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
771 /* wait for child to terminate */
772 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
773 /* child process has changed result file, so let profile functions know about it */
774 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
776 okChildInt("StartupInfoA", "cb", startup
.cb
);
777 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
778 result
= getChildString( "StartupInfoA", "lpTitle" );
779 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
780 "expected '%s' or null, got '%s'\n", selfname
, result
);
781 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
782 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
783 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
784 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
785 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
786 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
787 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
788 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
789 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
791 DeleteFileA(resfile
);
793 /* not so simplistic now */
794 memset(&startup
, 0, sizeof(startup
));
795 startup
.cb
= sizeof(startup
);
796 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
797 startup
.wShowWindow
= SW_SHOWNORMAL
;
798 startup
.lpTitle
= empty
;
799 startup
.lpDesktop
= desktop
;
800 startup
.dwXCountChars
= 0x12121212;
801 startup
.dwYCountChars
= 0x23232323;
802 startup
.dwX
= 0x34343434;
803 startup
.dwY
= 0x45454545;
804 startup
.dwXSize
= 0x56565656;
805 startup
.dwYSize
= 0x67676767;
806 startup
.dwFillAttribute
= 0xA55A;
808 get_file_name(resfile
);
809 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
810 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
811 /* wait for child to terminate */
812 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
813 /* child process has changed result file, so let profile functions know about it */
814 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
816 okChildInt("StartupInfoA", "cb", startup
.cb
);
817 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
818 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
819 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
820 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
821 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
822 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
823 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
824 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
825 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
826 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
827 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
829 DeleteFileA(resfile
);
831 /* not so simplistic now */
832 memset(&startup
, 0, sizeof(startup
));
833 startup
.cb
= sizeof(startup
);
834 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
835 startup
.wShowWindow
= SW_SHOWNORMAL
;
836 startup
.lpTitle
= empty
;
837 startup
.lpDesktop
= empty
;
838 startup
.dwXCountChars
= 0x12121212;
839 startup
.dwYCountChars
= 0x23232323;
840 startup
.dwX
= 0x34343434;
841 startup
.dwY
= 0x45454545;
842 startup
.dwXSize
= 0x56565656;
843 startup
.dwYSize
= 0x67676767;
844 startup
.dwFillAttribute
= 0xA55A;
846 get_file_name(resfile
);
847 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
848 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
849 /* wait for child to terminate */
850 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
851 /* child process has changed result file, so let profile functions know about it */
852 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
854 okChildInt("StartupInfoA", "cb", startup
.cb
);
855 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
856 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
857 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
858 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
859 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
860 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
861 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
862 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
863 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
864 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
865 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
867 DeleteFileA(resfile
);
869 /* TODO: test for A/W and W/A and W/W */
872 static void test_CommandLine(void)
874 char buffer
[MAX_PATH
], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
875 char buffer2
[MAX_PATH
];
876 PROCESS_INFORMATION info
;
877 STARTUPINFOA startup
;
880 memset(&startup
, 0, sizeof(startup
));
881 startup
.cb
= sizeof(startup
);
882 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
883 startup
.wShowWindow
= SW_SHOWNORMAL
;
886 get_file_name(resfile
);
887 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
888 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
889 /* wait for child to terminate */
890 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
891 /* child process has changed result file, so let profile functions know about it */
892 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
894 okChildInt("Arguments", "argcA", 5);
895 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
896 okChildString("Arguments", "argvA5", NULL
);
897 okChildString("Arguments", "CommandLineA", buffer
);
899 DeleteFileA(resfile
);
901 memset(&startup
, 0, sizeof(startup
));
902 startup
.cb
= sizeof(startup
);
903 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
904 startup
.wShowWindow
= SW_SHOWNORMAL
;
907 get_file_name(resfile
);
908 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname
, resfile
);
909 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
910 /* wait for child to terminate */
911 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
912 /* child process has changed result file, so let profile functions know about it */
913 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
915 okChildInt("Arguments", "argcA", 7);
916 okChildString("Arguments", "argvA4", "a\"b\\");
917 okChildString("Arguments", "argvA5", "c\"");
918 okChildString("Arguments", "argvA6", "d");
919 okChildString("Arguments", "argvA7", NULL
);
920 okChildString("Arguments", "CommandLineA", buffer
);
922 DeleteFileA(resfile
);
924 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
925 get_file_name(resfile
);
926 /* Use exename to avoid buffer containing things like 'C:' */
927 sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
928 SetLastError(0xdeadbeef);
929 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
930 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
931 /* wait for child to terminate */
932 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
933 /* child process has changed result file, so let profile functions know about it */
934 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
935 sprintf(buffer
, "./%s", exename
);
936 okChildString("Arguments", "argvA0", buffer
);
938 DeleteFileA(resfile
);
940 get_file_name(resfile
);
941 /* Use exename to avoid buffer containing things like 'C:' */
942 sprintf(buffer
, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
943 SetLastError(0xdeadbeef);
944 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
945 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
946 /* wait for child to terminate */
947 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
948 /* child process has changed result file, so let profile functions know about it */
949 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
950 sprintf(buffer
, ".\\%s", exename
);
951 okChildString("Arguments", "argvA0", buffer
);
953 DeleteFileA(resfile
);
955 get_file_name(resfile
);
956 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
957 assert ( lpFilePart
!= 0);
958 *(lpFilePart
-1 ) = 0;
959 p
= strrchr(fullpath
, '\\');
960 /* Use exename to avoid buffer containing things like 'C:' */
961 if (p
) sprintf(buffer
, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p
, exename
, resfile
);
962 else sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
963 SetLastError(0xdeadbeef);
964 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
965 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
966 /* wait for child to terminate */
967 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
968 /* child process has changed result file, so let profile functions know about it */
969 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
970 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
971 else sprintf(buffer
, "./%s", exename
);
972 okChildString("Arguments", "argvA0", buffer
);
974 DeleteFileA(resfile
);
977 get_file_name(resfile
);
978 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
979 assert ( lpFilePart
!= 0);
980 *(lpFilePart
-1 ) = 0;
981 p
= strrchr(fullpath
, '\\');
982 /* Use exename to avoid buffer containing things like 'C:' */
983 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
984 else sprintf(buffer
, "./%s", exename
);
985 sprintf(buffer2
, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile
);
986 SetLastError(0xdeadbeef);
987 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
988 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
989 /* wait for child to terminate */
990 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
991 /* child process has changed result file, so let profile functions know about it */
992 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
993 sprintf(buffer
, "tests/process.c dump %s", resfile
);
994 okChildString("Arguments", "argvA0", "dummy");
995 okChildString("Arguments", "CommandLineA", buffer2
);
996 okChildStringWA("Arguments", "CommandLineW", buffer2
);
998 DeleteFileA(resfile
);
1000 if (0) /* Test crashes on NT-based Windows. */
1002 /* Test NULL application name and command line parameters. */
1003 SetLastError(0xdeadbeef);
1004 ret
= CreateProcessA(NULL
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1005 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1006 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1007 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1012 /* Test empty application name parameter. */
1013 SetLastError(0xdeadbeef);
1014 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1015 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1016 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
1017 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
1018 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
1019 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1023 /* Test empty application name and command line parameters. */
1024 SetLastError(0xdeadbeef);
1025 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1026 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1027 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
1028 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
1029 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
1030 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1032 /* Test empty command line parameter. */
1033 SetLastError(0xdeadbeef);
1034 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1035 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1036 ok(GetLastError() == ERROR_FILE_NOT_FOUND
||
1037 GetLastError() == ERROR_PATH_NOT_FOUND
/* NT4 */ ||
1038 GetLastError() == ERROR_BAD_PATHNAME
/* Win98 */ ||
1039 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7 */,
1040 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1042 strcpy(buffer
, "doesnotexist.exe");
1043 strcpy(buffer2
, "does not exist.exe");
1045 /* Test nonexistent application name. */
1046 SetLastError(0xdeadbeef);
1047 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1048 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1049 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1051 SetLastError(0xdeadbeef);
1052 ret
= CreateProcessA(buffer2
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1053 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1054 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1056 /* Test nonexistent command line parameter. */
1057 SetLastError(0xdeadbeef);
1058 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1059 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1060 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1062 SetLastError(0xdeadbeef);
1063 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1064 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1065 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1068 static void test_Directory(void)
1070 char buffer
[MAX_PATH
];
1071 PROCESS_INFORMATION info
;
1072 STARTUPINFOA startup
;
1073 char windir
[MAX_PATH
];
1074 static CHAR cmdline
[] = "winver.exe";
1076 memset(&startup
, 0, sizeof(startup
));
1077 startup
.cb
= sizeof(startup
);
1078 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1079 startup
.wShowWindow
= SW_SHOWNORMAL
;
1082 get_file_name(resfile
);
1083 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1084 GetWindowsDirectoryA( windir
, sizeof(windir
) );
1085 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
1086 /* wait for child to terminate */
1087 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1088 /* child process has changed result file, so let profile functions know about it */
1089 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1091 okChildIString("Misc", "CurrDirA", windir
);
1093 DeleteFileA(resfile
);
1095 /* search PATH for the exe if directory is NULL */
1096 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1097 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
1099 /* if any directory is provided, don't search PATH, error on bad directory */
1100 SetLastError(0xdeadbeef);
1101 memset(&info
, 0, sizeof(info
));
1102 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
1103 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
1104 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1105 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
1108 static void test_Toolhelp(void)
1110 char buffer
[MAX_PATH
];
1111 STARTUPINFOA startup
;
1112 PROCESS_INFORMATION info
;
1113 HANDLE process
, thread
, snapshot
;
1119 memset(&startup
, 0, sizeof(startup
));
1120 startup
.cb
= sizeof(startup
);
1121 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1122 startup
.wShowWindow
= SW_SHOWNORMAL
;
1124 get_file_name(resfile
);
1125 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1126 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1127 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1128 CloseHandle(info
.hProcess
);
1129 CloseHandle(info
.hThread
);
1131 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1132 okChildInt("Toolhelp", "cntUsage", 0);
1133 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1134 okChildInt("Toolhelp", "th32ModuleID", 0);
1135 okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1136 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1137 okChildInt("Toolhelp", "dwFlags", 0);
1140 DeleteFileA(resfile
);
1142 get_file_name(resfile
);
1143 sprintf(buffer
, "\"%s\" tests/process.c nested \"%s\"", selfname
, resfile
);
1144 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
1145 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1147 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1148 ok(process
!= NULL
, "OpenProcess failed %u\n", GetLastError());
1149 CloseHandle(process
);
1151 CloseHandle(info
.hProcess
);
1152 CloseHandle(info
.hThread
);
1154 for (i
= 0; i
< 20; i
++)
1156 SetLastError(0xdeadbeef);
1157 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, info
.dwProcessId
);
1158 ok(process
|| GetLastError() == ERROR_INVALID_PARAMETER
, "OpenProcess failed %u\n", GetLastError());
1159 if (!process
) break;
1160 CloseHandle(process
);
1163 /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1164 ok(i
< 20 || broken(i
== 20), "process object not released\n");
1166 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
1167 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1168 memset(&pe
, 0, sizeof(pe
));
1169 pe
.dwSize
= sizeof(pe
);
1170 if (pProcess32First(snapshot
, &pe
))
1172 while (pe
.th32ParentProcessID
!= info
.dwProcessId
)
1173 if (!pProcess32Next(snapshot
, &pe
)) break;
1175 CloseHandle(snapshot
);
1176 ok(pe
.th32ParentProcessID
== info
.dwProcessId
, "failed to find nested child process\n");
1178 process
= OpenProcess(PROCESS_ALL_ACCESS_NT4
, FALSE
, pe
.th32ProcessID
);
1179 ok(process
!= NULL
, "OpenProcess failed %u\n", GetLastError());
1181 snapshot
= pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD
, 0);
1182 ok(snapshot
!= INVALID_HANDLE_VALUE
, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1183 memset(&te
, 0, sizeof(te
));
1184 te
.dwSize
= sizeof(te
);
1185 if (pThread32First(snapshot
, &te
))
1187 while (te
.th32OwnerProcessID
!= pe
.th32ProcessID
)
1188 if (!pThread32Next(snapshot
, &te
)) break;
1190 CloseHandle(snapshot
);
1191 ok(te
.th32OwnerProcessID
== pe
.th32ProcessID
, "failed to find suspended thread\n");
1193 thread
= OpenThread(THREAD_ALL_ACCESS_NT4
, FALSE
, te
.th32ThreadID
);
1194 ok(thread
!= NULL
, "OpenThread failed %u\n", GetLastError());
1195 ret
= ResumeThread(thread
);
1196 ok(ret
== 1, "expected 1, got %u\n", ret
);
1197 CloseHandle(thread
);
1199 ok(WaitForSingleObject(process
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1200 CloseHandle(process
);
1202 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1203 okChildInt("Toolhelp", "cntUsage", 0);
1204 okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1205 okChildInt("Toolhelp", "th32ModuleID", 0);
1206 okChildInt("Toolhelp", "th32ParentProcessID", info
.dwProcessId
);
1207 /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1208 okChildInt("Toolhelp", "dwFlags", 0);
1211 DeleteFileA(resfile
);
1214 static BOOL
is_str_env_drive_dir(const char* str
)
1216 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1217 str
[3] == '=' && str
[4] == str
[1];
1220 /* compared expected child's environment (in gesA) from actual
1221 * environment our child got
1223 static void cmpEnvironment(const char* gesA
)
1231 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1233 /* now look each parent env in child */
1234 if ((ptrA
= gesA
) != NULL
)
1238 for (i
= 0; i
< clen
; i
++)
1240 sprintf(key
, "env%d", i
);
1241 res
= getChildString("EnvironmentA", key
);
1242 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1246 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1248 ptrA
+= strlen(ptrA
) + 1;
1252 /* and each child env in parent */
1253 for (i
= 0; i
< clen
; i
++)
1255 sprintf(key
, "env%d", i
);
1256 res
= getChildString("EnvironmentA", key
);
1257 if ((ptrA
= gesA
) != NULL
)
1261 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1263 ptrA
+= strlen(ptrA
) + 1;
1265 if (!*ptrA
) ptrA
= NULL
;
1268 if (!is_str_env_drive_dir(res
))
1270 found
= ptrA
!= NULL
;
1271 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1273 /* else => should also test we get the right per drive default directory here... */
1277 static void test_Environment(void)
1279 char buffer
[MAX_PATH
];
1280 PROCESS_INFORMATION info
;
1281 STARTUPINFOA startup
;
1289 memset(&startup
, 0, sizeof(startup
));
1290 startup
.cb
= sizeof(startup
);
1291 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1292 startup
.wShowWindow
= SW_SHOWNORMAL
;
1295 get_file_name(resfile
);
1296 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1297 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1298 /* wait for child to terminate */
1299 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1300 /* child process has changed result file, so let profile functions know about it */
1301 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1303 env
= GetEnvironmentStringsA();
1304 cmpEnvironment(env
);
1306 DeleteFileA(resfile
);
1308 memset(&startup
, 0, sizeof(startup
));
1309 startup
.cb
= sizeof(startup
);
1310 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1311 startup
.wShowWindow
= SW_SHOWNORMAL
;
1314 get_file_name(resfile
);
1315 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1321 slen
= strlen(ptr
)+1;
1322 child_env_len
+= slen
;
1325 /* Add space for additional environment variables */
1326 child_env_len
+= 256;
1327 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1330 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1331 ptr
+= strlen(ptr
) + 1;
1332 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1333 ptr
+= strlen(ptr
) + 1;
1334 strcpy(ptr
, "FOO=BAR");
1335 ptr
+= strlen(ptr
) + 1;
1336 strcpy(ptr
, "BAR=FOOBAR");
1337 ptr
+= strlen(ptr
) + 1;
1338 /* copy all existing variables except:
1340 * - PATH (already set above)
1341 * - the directory definitions (=[A-Z]:=)
1343 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1345 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1346 strncmp(ptr2
, "WINELOADER=", 11) != 0 &&
1347 !is_str_env_drive_dir(ptr2
))
1350 ptr
+= strlen(ptr
) + 1;
1354 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1355 /* wait for child to terminate */
1356 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1357 /* child process has changed result file, so let profile functions know about it */
1358 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1360 cmpEnvironment(child_env
);
1362 HeapFree(GetProcessHeap(), 0, child_env
);
1363 FreeEnvironmentStringsA(env
);
1365 DeleteFileA(resfile
);
1368 static void test_SuspendFlag(void)
1370 char buffer
[MAX_PATH
];
1371 PROCESS_INFORMATION info
;
1372 STARTUPINFOA startup
, us
;
1376 /* let's start simplistic */
1377 memset(&startup
, 0, sizeof(startup
));
1378 startup
.cb
= sizeof(startup
);
1379 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1380 startup
.wShowWindow
= SW_SHOWNORMAL
;
1382 get_file_name(resfile
);
1383 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1384 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1386 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1388 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1389 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1391 /* wait for child to terminate */
1392 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1393 /* child process has changed result file, so let profile functions know about it */
1394 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1396 GetStartupInfoA(&us
);
1398 okChildInt("StartupInfoA", "cb", startup
.cb
);
1399 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1400 result
= getChildString( "StartupInfoA", "lpTitle" );
1401 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1402 "expected '%s' or null, got '%s'\n", selfname
, result
);
1403 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1404 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1405 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1406 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1407 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1408 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1409 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1410 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1411 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1413 DeleteFileA(resfile
);
1416 static void test_DebuggingFlag(void)
1418 char buffer
[MAX_PATH
];
1419 void *processbase
= NULL
;
1420 PROCESS_INFORMATION info
;
1421 STARTUPINFOA startup
, us
;
1426 /* let's start simplistic */
1427 memset(&startup
, 0, sizeof(startup
));
1428 startup
.cb
= sizeof(startup
);
1429 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1430 startup
.wShowWindow
= SW_SHOWNORMAL
;
1432 get_file_name(resfile
);
1433 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1434 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1436 /* get all startup events up to the entry point break exception */
1439 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1440 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1443 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1444 "first event: %d\n", de
.dwDebugEventCode
);
1445 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1447 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1448 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1449 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1450 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1452 ok(dbg
, "I have seen a debug event\n");
1453 /* wait for child to terminate */
1454 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1455 /* child process has changed result file, so let profile functions know about it */
1456 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1458 GetStartupInfoA(&us
);
1460 okChildInt("StartupInfoA", "cb", startup
.cb
);
1461 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1462 result
= getChildString( "StartupInfoA", "lpTitle" );
1463 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1464 "expected '%s' or null, got '%s'\n", selfname
, result
);
1465 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1466 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1467 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1468 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1469 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1470 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1471 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1472 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1473 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1475 DeleteFileA(resfile
);
1478 static BOOL
is_console(HANDLE h
)
1480 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1483 static void test_Console(void)
1485 char buffer
[MAX_PATH
];
1486 PROCESS_INFORMATION info
;
1487 STARTUPINFOA startup
, us
;
1488 SECURITY_ATTRIBUTES sa
;
1489 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1490 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1491 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1493 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1494 const char* msg
= "This is a std-handle inheritance test.";
1496 BOOL run_tests
= TRUE
;
1499 memset(&startup
, 0, sizeof(startup
));
1500 startup
.cb
= sizeof(startup
);
1501 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1502 startup
.wShowWindow
= SW_SHOWNORMAL
;
1504 sa
.nLength
= sizeof(sa
);
1505 sa
.lpSecurityDescriptor
= NULL
;
1506 sa
.bInheritHandle
= TRUE
;
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 /* first, we need to be sure we're attached to a console */
1512 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1514 /* we're not attached to a console, let's do it */
1516 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1517 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1519 /* now verify everything's ok */
1520 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1521 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1522 startup
.hStdError
= startup
.hStdOutput
;
1524 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1525 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
), "Getting console in mode\n");
1526 ok(GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console out mode\n");
1527 cpIn
= GetConsoleCP();
1528 cpOut
= GetConsoleOutputCP();
1530 get_file_name(resfile
);
1531 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" console", selfname
, resfile
);
1532 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1534 /* wait for child to terminate */
1535 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1536 /* child process has changed result file, so let profile functions know about it */
1537 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1539 /* now get the modification the child has made, and resets parents expected values */
1540 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1541 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
), "Getting console in mode\n");
1542 ok(GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console out mode\n");
1544 SetConsoleMode(startup
.hStdInput
, modeIn
);
1545 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1547 cpInC
= GetConsoleCP();
1548 cpOutC
= GetConsoleOutputCP();
1550 /* Try to set invalid CP */
1551 SetLastError(0xdeadbeef);
1552 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1553 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1554 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1555 "GetLastError: expecting %u got %u\n",
1556 ERROR_INVALID_PARAMETER
, GetLastError());
1557 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1561 SetLastError(0xdeadbeef);
1562 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1563 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1564 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1565 "GetLastError: expecting %u got %u\n",
1566 ERROR_INVALID_PARAMETER
, GetLastError());
1569 SetConsoleOutputCP(cpOut
);
1571 GetStartupInfoA(&us
);
1573 okChildInt("StartupInfoA", "cb", startup
.cb
);
1574 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1575 result
= getChildString( "StartupInfoA", "lpTitle" );
1576 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1577 "expected '%s' or null, got '%s'\n", selfname
, result
);
1578 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1579 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1580 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1581 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1582 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1583 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1584 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1585 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1586 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1588 /* check child correctly inherited the console */
1589 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1590 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1591 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1592 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1593 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1594 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1595 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1596 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1597 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1598 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1599 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1600 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1601 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1602 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1603 okChildInt("Console", "InputCP", cpIn
);
1604 okChildInt("Console", "OutputCP", cpOut
);
1605 okChildInt("Console", "InputMode", modeIn
);
1606 okChildInt("Console", "OutputMode", modeOut
);
1610 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1611 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1614 win_skip("Setting the codepage is not implemented\n");
1616 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1617 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1618 trace("cursor position(X): %d/%d\n",sbi
.dwCursorPosition
.X
, sbiC
.dwCursorPosition
.X
);
1619 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1622 DeleteFileA(resfile
);
1624 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1625 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1626 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1627 "Duplicating as inheritable child-output pipe\n");
1628 CloseHandle(hChildOut
);
1630 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1631 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1632 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1633 "Duplicating as inheritable child-input pipe\n");
1634 CloseHandle(hChildIn
);
1636 memset(&startup
, 0, sizeof(startup
));
1637 startup
.cb
= sizeof(startup
);
1638 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1639 startup
.wShowWindow
= SW_SHOWNORMAL
;
1640 startup
.hStdInput
= hChildInInh
;
1641 startup
.hStdOutput
= hChildOutInh
;
1642 startup
.hStdError
= hChildOutInh
;
1644 get_file_name(resfile
);
1645 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname
, resfile
);
1646 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1647 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1648 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1650 msg_len
= strlen(msg
) + 1;
1651 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1652 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1653 memset(buffer
, 0, sizeof(buffer
));
1654 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1655 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1657 /* wait for child to terminate */
1658 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1659 /* child process has changed result file, so let profile functions know about it */
1660 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1662 okChildString("StdHandle", "msg", msg
);
1665 DeleteFileA(resfile
);
1668 static void test_ExitCode(void)
1670 char buffer
[MAX_PATH
];
1671 PROCESS_INFORMATION info
;
1672 STARTUPINFOA startup
;
1675 /* let's start simplistic */
1676 memset(&startup
, 0, sizeof(startup
));
1677 startup
.cb
= sizeof(startup
);
1678 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1679 startup
.wShowWindow
= SW_SHOWNORMAL
;
1681 get_file_name(resfile
);
1682 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname
, resfile
);
1683 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1685 /* wait for child to terminate */
1686 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1687 /* child process has changed result file, so let profile functions know about it */
1688 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1690 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1691 okChildInt("ExitCode", "value", code
);
1694 DeleteFileA(resfile
);
1697 static void test_OpenProcess(void)
1701 MEMORY_BASIC_INFORMATION info
;
1702 SIZE_T dummy
, read_bytes
;
1705 /* not exported in all windows versions */
1706 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1707 win_skip("VirtualAllocEx not found\n");
1711 /* without PROCESS_VM_OPERATION */
1712 hproc
= OpenProcess(PROCESS_ALL_ACCESS_NT4
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1713 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1715 SetLastError(0xdeadbeef);
1716 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1717 ok(!addr1
, "VirtualAllocEx should fail\n");
1718 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1721 win_skip("VirtualAllocEx not implemented\n");
1724 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1726 read_bytes
= 0xdeadbeef;
1727 SetLastError(0xdeadbeef);
1728 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1729 ok(ret
, "ReadProcessMemory error %d\n", GetLastError());
1730 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1734 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1735 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1737 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1738 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1740 /* without PROCESS_QUERY_INFORMATION */
1741 SetLastError(0xdeadbeef);
1742 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1743 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1744 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1746 /* without PROCESS_VM_READ */
1747 read_bytes
= 0xdeadbeef;
1748 SetLastError(0xdeadbeef);
1749 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1750 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1751 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1752 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1756 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1758 memset(&info
, 0xcc, sizeof(info
));
1759 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1760 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1762 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1763 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1764 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1765 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1766 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1767 /* NT reports Protect == 0 for a not committed memory block */
1768 ok(info
.Protect
== 0 /* NT */ ||
1769 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1770 "%x != PAGE_NOACCESS\n", info
.Protect
);
1771 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1773 SetLastError(0xdeadbeef);
1774 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1775 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1776 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1780 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
1783 SetLastError(0xdeadbeef);
1784 memset(&info
, 0xcc, sizeof(info
));
1785 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1786 if (read_bytes
) /* win8 */
1788 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1789 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1790 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1791 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1792 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1793 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1794 ok(info
.Protect
== 0, "%x != PAGE_NOACCESS\n", info
.Protect
);
1795 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1797 else /* before win8 */
1798 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1800 SetLastError(0xdeadbeef);
1801 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1802 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1803 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1808 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1811 static void test_GetProcessVersion(void)
1813 static char cmdline
[] = "winver.exe";
1814 PROCESS_INFORMATION pi
;
1818 SetLastError(0xdeadbeef);
1819 ret
= GetProcessVersion(0);
1820 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1822 SetLastError(0xdeadbeef);
1823 ret
= GetProcessVersion(GetCurrentProcessId());
1824 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1826 memset(&si
, 0, sizeof(si
));
1828 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1829 si
.wShowWindow
= SW_HIDE
;
1830 SetLastError(0xdeadbeef);
1831 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1832 ok(ret
, "CreateProcess error %u\n", GetLastError());
1834 SetLastError(0xdeadbeef);
1835 ret
= GetProcessVersion(pi
.dwProcessId
);
1836 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1838 SetLastError(0xdeadbeef);
1839 ret
= TerminateProcess(pi
.hProcess
, 0);
1840 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1842 CloseHandle(pi
.hProcess
);
1843 CloseHandle(pi
.hThread
);
1846 static void test_GetProcessImageFileNameA(void)
1849 CHAR process
[MAX_PATH
];
1850 static const char harddisk
[] = "\\Device\\HarddiskVolume";
1852 if (!pK32GetProcessImageFileNameA
)
1854 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1858 /* callers must guess the buffer size */
1859 SetLastError(0xdeadbeef);
1860 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL
, 0);
1861 ok(!rc
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
1862 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc
, GetLastError());
1865 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), process
, sizeof(process
));
1866 expect_eq_d(rc
, lstrlenA(process
));
1867 if (strncmp(process
, harddisk
, lstrlenA(harddisk
)))
1869 todo_wine
win_skip("%s is probably on a network share, skipping tests\n", process
);
1873 if (!pQueryFullProcessImageNameA
)
1874 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1877 CHAR image
[MAX_PATH
];
1880 length
= sizeof(image
);
1881 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE
, image
, &length
));
1882 expect_eq_d(length
, lstrlenA(image
));
1883 ok(lstrcmpiA(process
, image
) == 0, "expected '%s' to be equal to '%s'\n", process
, image
);
1887 static void test_QueryFullProcessImageNameA(void)
1889 #define INIT_STR "Just some words"
1891 CHAR buf
[MAX_PATH
], module
[MAX_PATH
];
1893 if (!pQueryFullProcessImageNameA
)
1895 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1900 SetLastError(0); /* old Windows don't reset it on success */
1901 size
= GetModuleFileNameA(NULL
, module
, sizeof(module
));
1902 ok(size
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
, "GetModuleFileName failed: %u le=%u\n", size
, GetLastError());
1904 /* get the buffer length without \0 terminator */
1905 length
= sizeof(buf
);
1906 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1907 expect_eq_d(length
, lstrlenA(buf
));
1908 ok((buf
[0] == '\\' && buf
[1] == '\\') ||
1909 lstrcmpiA(buf
, module
) == 0, "expected %s to match %s\n", buf
, module
);
1911 /* when the buffer is too small
1912 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1913 * - the size variable is not modified
1914 * tested with the biggest too small size
1917 sprintf(buf
,INIT_STR
);
1918 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1919 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1920 expect_eq_d(length
, size
);
1921 expect_eq_s(INIT_STR
, buf
);
1923 /* retest with smaller buffer size
1926 sprintf(buf
,INIT_STR
);
1927 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1928 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1929 expect_eq_d(4, size
);
1930 expect_eq_s(INIT_STR
, buf
);
1932 /* this is a difference between the ascii and the unicode version
1933 * the unicode version crashes when the size is big enough to hold
1934 * the result while the ascii version throws an error
1937 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1938 expect_eq_d(1024, size
);
1939 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1942 static void test_QueryFullProcessImageNameW(void)
1945 WCHAR module_name
[1024], device
[1024];
1946 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
1950 if (!pQueryFullProcessImageNameW
)
1952 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1956 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1958 /* GetCurrentProcess pseudo-handle */
1959 size
= sizeof(buf
) / sizeof(buf
[0]);
1960 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
1961 expect_eq_d(lstrlenW(buf
), size
);
1962 expect_eq_ws_i(buf
, module_name
);
1964 hSelf
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
1966 size
= sizeof(buf
) / sizeof(buf
[0]);
1967 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1968 expect_eq_d(lstrlenW(buf
), size
);
1969 expect_eq_ws_i(buf
, module_name
);
1971 /* Buffer too small */
1972 size
= lstrlenW(module_name
)/2;
1973 lstrcpyW(buf
, deviceW
);
1974 SetLastError(0xdeadbeef);
1975 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1976 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1977 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1978 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
1980 /* Too small - not space for NUL terminator */
1981 size
= lstrlenW(module_name
);
1982 SetLastError(0xdeadbeef);
1983 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1984 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
1985 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1989 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
1990 expect_eq_d(0, size
);
1991 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1993 /* Buffer too small */
1994 size
= lstrlenW(module_name
)/2;
1995 SetLastError(0xdeadbeef);
1996 lstrcpyW(buf
, module_name
);
1997 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1998 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1999 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
2000 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
2004 size
= sizeof(buf
) / sizeof(buf
[0]);
2005 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
2006 expect_eq_d(lstrlenW(buf
), size
);
2007 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
2008 ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
2010 module_name
[2] = '\0';
2012 size
= QueryDosDeviceW(module_name
, device
, sizeof(device
)/sizeof(device
[0]));
2013 ok(size
, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2014 len
= lstrlenW(device
);
2015 ok(size
>= len
+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size
, len
, wine_dbgstr_w(device
));
2017 if (size
>= lstrlenW(buf
))
2019 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2023 ok(buf
[len
] == '\\', "expected '%c' to be a '\\' in %s\n", buf
[len
], wine_dbgstr_w(module_name
));
2025 ok(lstrcmpiW(device
, buf
) == 0, "expected %s to match %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
2026 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));
2032 static void test_Handles(void)
2034 HANDLE handle
= GetCurrentProcess();
2039 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
2040 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
2041 "invalid current process handle %p\n", handle
);
2042 ret
= GetExitCodeProcess( handle
, &code
);
2043 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
2045 /* truncated handle */
2046 SetLastError( 0xdeadbeef );
2047 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
2048 ret
= GetExitCodeProcess( handle
, &code
);
2049 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2050 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
2051 /* sign-extended handle */
2052 SetLastError( 0xdeadbeef );
2053 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
2054 ret
= GetExitCodeProcess( handle
, &code
);
2055 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
2056 /* invalid high-word */
2057 SetLastError( 0xdeadbeef );
2058 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
2059 ret
= GetExitCodeProcess( handle
, &code
);
2060 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
2061 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
2064 handle
= GetStdHandle( STD_ERROR_HANDLE
);
2065 ok( handle
!= 0, "handle %p\n", handle
);
2066 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
2067 0, TRUE
, DUPLICATE_SAME_ACCESS
);
2068 SetStdHandle( STD_ERROR_HANDLE
, h3
);
2069 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
2070 h2
= GetStdHandle( STD_ERROR_HANDLE
);
2072 broken( h2
== h3
) || /* nt4, w2k */
2073 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
2074 "wrong handle %p/%p\n", h2
, h3
);
2075 SetStdHandle( STD_ERROR_HANDLE
, handle
);
2078 static void test_IsWow64Process(void)
2080 PROCESS_INFORMATION pi
;
2084 static char cmdline
[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2085 static char cmdline_wow64
[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2087 if (!pIsWow64Process
)
2089 skip("IsWow64Process is not available\n");
2093 memset(&si
, 0, sizeof(si
));
2095 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2096 si
.wShowWindow
= SW_HIDE
;
2097 ret
= CreateProcessA(NULL
, cmdline_wow64
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2100 trace("Created process %s\n", cmdline_wow64
);
2102 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2103 ok(ret
, "IsWow64Process failed.\n");
2104 ok(is_wow64
, "is_wow64 returned FALSE.\n");
2106 ret
= TerminateProcess(pi
.hProcess
, 0);
2107 ok(ret
, "TerminateProcess error\n");
2109 CloseHandle(pi
.hProcess
);
2110 CloseHandle(pi
.hThread
);
2113 memset(&si
, 0, sizeof(si
));
2115 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2116 si
.wShowWindow
= SW_HIDE
;
2117 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2120 trace("Created process %s\n", cmdline
);
2122 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
2123 ok(ret
, "IsWow64Process failed.\n");
2124 ok(!is_wow64
, "is_wow64 returned TRUE.\n");
2126 ret
= TerminateProcess(pi
.hProcess
, 0);
2127 ok(ret
, "TerminateProcess error\n");
2129 CloseHandle(pi
.hProcess
);
2130 CloseHandle(pi
.hThread
);
2134 static void test_SystemInfo(void)
2136 SYSTEM_INFO si
, nsi
;
2139 if (!pGetNativeSystemInfo
)
2141 win_skip("GetNativeSystemInfo is not available\n");
2145 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
2148 pGetNativeSystemInfo(&nsi
);
2151 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
2153 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
2154 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2155 S(U(nsi
)).wProcessorArchitecture
);
2156 ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
,
2157 "Expected PROCESSOR_AMD_X8664, got %d\n",
2158 nsi
.dwProcessorType
);
2163 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
2164 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2165 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
2166 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
2167 "Expected no difference for dwProcessorType, got %d and %d\n",
2168 si
.dwProcessorType
, nsi
.dwProcessorType
);
2172 static void test_RegistryQuota(void)
2175 DWORD max_quota
, used_quota
;
2177 if (!pGetSystemRegistryQuota
)
2179 win_skip("GetSystemRegistryQuota is not available\n");
2183 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
2185 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2187 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
2189 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2191 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
2193 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2195 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
2197 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2200 static void test_TerminateProcess(void)
2202 static char cmdline
[] = "winver.exe";
2203 PROCESS_INFORMATION pi
;
2206 HANDLE dummy
, thread
;
2208 memset(&si
, 0, sizeof(si
));
2210 SetLastError(0xdeadbeef);
2211 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2212 ok(ret
, "CreateProcess error %u\n", GetLastError());
2214 SetLastError(0xdeadbeef);
2215 thread
= CreateRemoteThread(pi
.hProcess
, NULL
, 0, (void *)0xdeadbeef, NULL
, CREATE_SUSPENDED
, &ret
);
2216 ok(thread
!= 0, "CreateRemoteThread error %d\n", GetLastError());
2218 /* create a not closed thread handle duplicate in the target process */
2219 SetLastError(0xdeadbeef);
2220 ret
= DuplicateHandle(GetCurrentProcess(), thread
, pi
.hProcess
, &dummy
,
2221 0, FALSE
, DUPLICATE_SAME_ACCESS
);
2222 ok(ret
, "DuplicateHandle error %u\n", GetLastError());
2224 SetLastError(0xdeadbeef);
2225 ret
= TerminateThread(thread
, 0);
2226 ok(ret
, "TerminateThread error %u\n", GetLastError());
2227 CloseHandle(thread
);
2229 SetLastError(0xdeadbeef);
2230 ret
= TerminateProcess(pi
.hProcess
, 0);
2231 ok(ret
, "TerminateProcess error %u\n", GetLastError());
2233 CloseHandle(pi
.hProcess
);
2234 CloseHandle(pi
.hThread
);
2237 static void test_DuplicateHandle(void)
2239 char path
[MAX_PATH
], file_name
[MAX_PATH
];
2240 HANDLE f
, fmin
, out
;
2244 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2245 GetCurrentProcess(), &out
, 0, FALSE
,
2246 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2247 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2248 r
= GetHandleInformation(out
, &info
);
2249 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2250 ok(info
== 0, "info = %x\n", info
);
2251 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2254 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2255 GetCurrentProcess(), &out
, 0, TRUE
,
2256 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2257 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2258 r
= GetHandleInformation(out
, &info
);
2259 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2260 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2261 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2264 GetTempPathA(MAX_PATH
, path
);
2265 GetTempFileNameA(path
, "wt", 0, file_name
);
2266 f
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
2267 if (f
== INVALID_HANDLE_VALUE
)
2269 ok(0, "could not create %s\n", file_name
);
2273 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2274 0, FALSE
, 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
== 0, "info = %x\n", info
);
2281 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2282 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2283 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2284 ok(f
== out
, "f != out\n");
2285 r
= GetHandleInformation(out
, &info
);
2286 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2287 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2289 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, HANDLE_FLAG_PROTECT_FROM_CLOSE
);
2290 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2291 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2292 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2293 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2294 ok(f
!= out
, "f == out\n");
2295 r
= GetHandleInformation(out
, &info
);
2296 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2297 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2298 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, 0);
2299 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2301 /* Test if DuplicateHandle allocates first free handle */
2312 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2313 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2314 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2315 ok(f
== out
, "f != out\n");
2317 DeleteFileA(file_name
);
2319 f
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2322 skip("DuplicateHandle on console handle\n");
2327 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2328 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2329 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2330 todo_wine
ok(f
!= out
, "f == out\n");
2334 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2335 static void _test_completion(int line
, HANDLE port
, DWORD ekey
, ULONG_PTR evalue
, ULONG_PTR eoverlapped
, DWORD wait
)
2337 LPOVERLAPPED overlapped
;
2342 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, wait
);
2344 ok_(__FILE__
, line
)(ret
, "GetQueuedCompletionStatus: %x\n", GetLastError());
2347 ok_(__FILE__
, line
)(key
== ekey
, "unexpected key %x\n", key
);
2348 ok_(__FILE__
, line
)(value
== evalue
, "unexpected value %p\n", (void *)value
);
2349 ok_(__FILE__
, line
)(overlapped
== (LPOVERLAPPED
)eoverlapped
, "unexpected overlapped %p\n", overlapped
);
2353 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2354 static void _create_process(int line
, const char *command
, LPPROCESS_INFORMATION pi
)
2357 char buffer
[MAX_PATH
];
2358 STARTUPINFOA si
= {0};
2360 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, command
);
2362 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, pi
);
2363 ok_(__FILE__
, line
)(ret
, "CreateProcess error %u\n", GetLastError());
2367 static void test_IsProcessInJob(void)
2370 PROCESS_INFORMATION pi
;
2374 if (!pIsProcessInJob
)
2376 win_skip("IsProcessInJob not available.\n");
2380 job
= pCreateJobObjectW(NULL
, NULL
);
2381 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2383 job2
= pCreateJobObjectW(NULL
, NULL
);
2384 ok(job2
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2386 create_process("wait", &pi
);
2389 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2390 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2391 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2394 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2395 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2396 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2399 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2400 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2401 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2403 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2404 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2407 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2408 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2409 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2412 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2413 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2414 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2417 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2418 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2419 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2421 TerminateProcess(pi
.hProcess
, 0);
2423 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2424 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2427 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2428 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2429 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2431 CloseHandle(pi
.hProcess
);
2432 CloseHandle(pi
.hThread
);
2437 static void test_TerminateJobObject(void)
2440 PROCESS_INFORMATION pi
;
2444 job
= pCreateJobObjectW(NULL
, NULL
);
2445 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2447 create_process("wait", &pi
);
2449 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2450 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2452 ret
= pTerminateJobObject(job
, 123);
2453 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2455 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2456 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2457 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2459 ret
= GetExitCodeProcess(pi
.hProcess
, &dwret
);
2460 ok(ret
, "GetExitCodeProcess error %u\n", GetLastError());
2461 ok(dwret
== 123 || broken(dwret
== 0) /* randomly fails on Win 2000 / XP */,
2462 "wrong exitcode %u\n", dwret
);
2464 CloseHandle(pi
.hProcess
);
2465 CloseHandle(pi
.hThread
);
2467 /* Test adding an already terminated process to a job object */
2468 create_process("exit", &pi
);
2470 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2471 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2473 SetLastError(0xdeadbeef);
2474 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2475 ok(!ret
, "AssignProcessToJobObject unexpectedly succeeded\n");
2476 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2478 CloseHandle(pi
.hProcess
);
2479 CloseHandle(pi
.hThread
);
2484 static void test_QueryInformationJobObject(void)
2486 char buf
[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST
) + sizeof(ULONG_PTR
) * 4];
2487 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2488 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info
;
2489 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit_info
= &ext_limit_info
.BasicLimitInformation
;
2490 DWORD dwret
, ret_len
;
2491 PROCESS_INFORMATION pi
[2];
2495 job
= pCreateJobObjectW(NULL
, NULL
);
2496 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2498 /* Only active processes are returned */
2499 create_process("exit", &pi
[0]);
2500 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2501 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2502 dwret
= WaitForSingleObject(pi
[0].hProcess
, 1000);
2503 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2505 CloseHandle(pi
[0].hProcess
);
2506 CloseHandle(pi
[0].hThread
);
2508 create_process("wait", &pi
[0]);
2509 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2510 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2512 create_process("wait", &pi
[1]);
2513 ret
= pAssignProcessToJobObject(job
, pi
[1].hProcess
);
2514 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2516 SetLastError(0xdeadbeef);
2517 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2518 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
), &ret_len
);
2519 ok(!ret
, "QueryInformationJobObject expected failure\n");
2520 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2522 SetLastError(0xdeadbeef);
2523 memset(buf
, 0, sizeof(buf
));
2524 pid_list
->NumberOfAssignedProcesses
= 42;
2525 pid_list
->NumberOfProcessIdsInList
= 42;
2526 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2527 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[1]), &ret_len
);
2529 ok(!ret
, "QueryInformationJobObject expected failure\n");
2531 expect_eq_d(ERROR_MORE_DATA
, GetLastError());
2535 expect_eq_d(42, pid_list
->NumberOfAssignedProcesses
);
2537 expect_eq_d(42, pid_list
->NumberOfProcessIdsInList
);
2540 memset(buf
, 0, sizeof(buf
));
2541 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2542 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2545 if (pid_list
->NumberOfAssignedProcesses
== 3) /* Win 8 */
2546 win_skip("Number of assigned processes broken on Win 8\n");
2549 ULONG_PTR
*list
= pid_list
->ProcessIdList
;
2552 ok(ret_len
== FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[2]),
2553 "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2556 expect_eq_d(2, pid_list
->NumberOfAssignedProcesses
);
2558 expect_eq_d(2, pid_list
->NumberOfProcessIdsInList
);
2560 expect_eq_d(pi
[0].dwProcessId
, list
[0]);
2562 expect_eq_d(pi
[1].dwProcessId
, list
[1]);
2566 /* test JobObjectBasicLimitInformation */
2567 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2568 sizeof(*basic_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(basic_limit_info
, 0x11, sizeof(*basic_limit_info
));
2574 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2575 sizeof(*basic_limit_info
), &ret_len
);
2576 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2577 ok(ret_len
== sizeof(*basic_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2578 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2580 /* test JobObjectExtendedLimitInformation */
2581 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2582 sizeof(ext_limit_info
) - 1, &ret_len
);
2583 ok(!ret
, "QueryInformationJobObject expected failure\n");
2584 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2586 ret_len
= 0xdeadbeef;
2587 memset(&ext_limit_info
, 0x11, sizeof(ext_limit_info
));
2588 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2589 sizeof(ext_limit_info
), &ret_len
);
2590 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2591 ok(ret_len
== sizeof(ext_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2592 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2594 TerminateProcess(pi
[0].hProcess
, 0);
2595 CloseHandle(pi
[0].hProcess
);
2596 CloseHandle(pi
[0].hThread
);
2598 TerminateProcess(pi
[1].hProcess
, 0);
2599 CloseHandle(pi
[1].hProcess
);
2600 CloseHandle(pi
[1].hThread
);
2605 static void test_CompletionPort(void)
2607 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
2608 PROCESS_INFORMATION pi
;
2613 job
= pCreateJobObjectW(NULL
, NULL
);
2614 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2616 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
2617 ok(port
!= NULL
, "CreateIoCompletionPort error %u\n", GetLastError());
2619 port_info
.CompletionKey
= job
;
2620 port_info
.CompletionPort
= port
;
2621 ret
= pSetInformationJobObject(job
, JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
2622 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2624 create_process("wait", &pi
);
2626 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2627 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2629 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2631 TerminateProcess(pi
.hProcess
, 0);
2632 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2633 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2635 test_completion(port
, JOB_OBJECT_MSG_EXIT_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2636 test_completion(port
, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
, (DWORD_PTR
)job
, 0, 100);
2638 CloseHandle(pi
.hProcess
);
2639 CloseHandle(pi
.hThread
);
2644 static void test_KillOnJobClose(void)
2646 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2647 PROCESS_INFORMATION pi
;
2652 job
= pCreateJobObjectW(NULL
, NULL
);
2653 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2655 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
;
2656 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2657 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
2659 win_skip("Kill on job close limit not available\n");
2662 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2664 create_process("wait", &pi
);
2666 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2667 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2671 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2672 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2673 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2675 CloseHandle(pi
.hProcess
);
2676 CloseHandle(pi
.hThread
);
2679 static void test_WaitForJobObject(void)
2682 PROCESS_INFORMATION pi
;
2686 /* test waiting for a job object when the process is killed */
2687 job
= pCreateJobObjectW(NULL
, NULL
);
2688 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2690 dwret
= WaitForSingleObject(job
, 100);
2691 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2693 create_process("wait", &pi
);
2695 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2696 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2698 dwret
= WaitForSingleObject(job
, 100);
2699 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2701 ret
= pTerminateJobObject(job
, 123);
2702 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2704 dwret
= WaitForSingleObject(job
, 500);
2705 ok(dwret
== WAIT_OBJECT_0
|| broken(dwret
== WAIT_TIMEOUT
),
2706 "WaitForSingleObject returned %u\n", dwret
);
2708 if (dwret
== WAIT_TIMEOUT
) /* Win 2000/XP */
2713 ok(0, "HACK: Killing process to speed up the test\n");
2714 TerminateProcess(pi
.hProcess
, 0);
2717 CloseHandle(pi
.hProcess
);
2718 CloseHandle(pi
.hThread
);
2720 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2724 /* the object is not reset immediately */
2725 dwret
= WaitForSingleObject(job
, 100);
2726 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2728 CloseHandle(pi
.hProcess
);
2729 CloseHandle(pi
.hThread
);
2731 /* creating a new process doesn't reset the signalled state */
2732 create_process("wait", &pi
);
2734 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2735 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2737 dwret
= WaitForSingleObject(job
, 100);
2738 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2740 ret
= pTerminateJobObject(job
, 123);
2741 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2743 CloseHandle(pi
.hProcess
);
2744 CloseHandle(pi
.hThread
);
2748 /* repeat the test, but this time the process terminates properly */
2749 job
= pCreateJobObjectW(NULL
, NULL
);
2750 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2752 dwret
= WaitForSingleObject(job
, 100);
2753 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2755 create_process("exit", &pi
);
2757 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2758 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2760 dwret
= WaitForSingleObject(job
, 100);
2761 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2763 CloseHandle(pi
.hProcess
);
2764 CloseHandle(pi
.hThread
);
2768 static HANDLE
test_AddSelfToJob(void)
2773 job
= pCreateJobObjectW(NULL
, NULL
);
2774 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2776 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
2777 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2782 static void test_jobInheritance(HANDLE job
)
2784 char buffer
[MAX_PATH
];
2785 PROCESS_INFORMATION pi
;
2786 STARTUPINFOA si
= {0};
2790 if (!pIsProcessInJob
)
2792 win_skip("IsProcessInJob not available.\n");
2796 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2798 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2799 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2802 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2803 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2804 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2806 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2807 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2809 CloseHandle(pi
.hProcess
);
2810 CloseHandle(pi
.hThread
);
2813 static void test_BreakawayOk(HANDLE job
)
2815 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2816 PROCESS_INFORMATION pi
;
2817 STARTUPINFOA si
= {0};
2818 char buffer
[MAX_PATH
];
2822 if (!pIsProcessInJob
)
2824 win_skip("IsProcessInJob not available.\n");
2828 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2830 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2831 ok(!ret
, "CreateProcessA expected failure\n");
2832 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2836 TerminateProcess(pi
.hProcess
, 0);
2838 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2839 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2841 CloseHandle(pi
.hProcess
);
2842 CloseHandle(pi
.hThread
);
2845 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
2846 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2847 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2849 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2850 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2852 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2853 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2854 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2856 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2857 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2859 CloseHandle(pi
.hProcess
);
2860 CloseHandle(pi
.hThread
);
2862 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
2863 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2864 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2866 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2867 ok(ret
, "CreateProcess error %u\n", GetLastError());
2869 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2870 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2871 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2873 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2874 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2876 CloseHandle(pi
.hProcess
);
2877 CloseHandle(pi
.hThread
);
2879 /* unset breakaway ok */
2880 limit_info
.BasicLimitInformation
.LimitFlags
= 0;
2881 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2882 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2885 static void test_StartupNoConsole(void)
2888 char buffer
[MAX_PATH
];
2889 STARTUPINFOA startup
;
2890 PROCESS_INFORMATION info
;
2892 memset(&startup
, 0, sizeof(startup
));
2893 startup
.cb
= sizeof(startup
);
2894 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
2895 startup
.wShowWindow
= SW_SHOWNORMAL
;
2896 get_file_name(resfile
);
2897 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
2898 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
2899 &info
), "CreateProcess\n");
2900 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
2901 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
2902 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
2903 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
2904 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
2905 okChildInt("TEB", "hStdInput", 0);
2906 okChildInt("TEB", "hStdOutput", 0);
2907 okChildInt("TEB", "hStdError", 0);
2909 DeleteFileA(resfile
);
2913 static void test_DetachConsoleHandles(void)
2916 char buffer
[MAX_PATH
];
2917 STARTUPINFOA startup
;
2918 PROCESS_INFORMATION info
;
2921 memset(&startup
, 0, sizeof(startup
));
2922 startup
.cb
= sizeof(startup
);
2923 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
2924 startup
.wShowWindow
= SW_SHOWNORMAL
;
2925 startup
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
2926 startup
.hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
2927 startup
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
2928 get_file_name(resfile
);
2929 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
2930 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
2931 &info
), "CreateProcess\n");
2932 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
2933 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
2935 result
= GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile
);
2936 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
2937 result
= GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile
);
2938 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
2939 result
= GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile
);
2940 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
2941 result
= GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile
);
2942 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
2943 result
= GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile
);
2944 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
2945 result
= GetPrivateProfileIntA("TEB", "hStdError", 0, resfile
);
2946 ok(result
!= 0 && result
!= (UINT
)INVALID_HANDLE_VALUE
, "bad handle %x\n", result
);
2949 DeleteFileA(resfile
);
2953 static void test_DetachStdHandles(void)
2956 char buffer
[MAX_PATH
], tempfile
[MAX_PATH
];
2957 STARTUPINFOA startup
;
2958 PROCESS_INFORMATION info
;
2959 HANDLE hstdin
, hstdout
, hstderr
, htemp
;
2962 hstdin
= GetStdHandle(STD_INPUT_HANDLE
);
2963 hstdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
2964 hstderr
= GetStdHandle(STD_ERROR_HANDLE
);
2966 get_file_name(tempfile
);
2967 htemp
= CreateFileA(tempfile
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2968 ok(htemp
!= INVALID_HANDLE_VALUE
, "failed opening temporary file\n");
2970 memset(&startup
, 0, sizeof(startup
));
2971 startup
.cb
= sizeof(startup
);
2972 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
2973 startup
.wShowWindow
= SW_SHOWNORMAL
;
2974 get_file_name(resfile
);
2975 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
2977 SetStdHandle(STD_INPUT_HANDLE
, htemp
);
2978 SetStdHandle(STD_OUTPUT_HANDLE
, htemp
);
2979 SetStdHandle(STD_ERROR_HANDLE
, htemp
);
2981 res
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
2984 SetStdHandle(STD_INPUT_HANDLE
, hstdin
);
2985 SetStdHandle(STD_OUTPUT_HANDLE
, hstdout
);
2986 SetStdHandle(STD_ERROR_HANDLE
, hstderr
);
2988 ok(res
, "CreateProcess failed\n");
2989 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
2990 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
2991 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
2992 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
2993 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
2994 okChildInt("TEB", "hStdInput", 0);
2995 okChildInt("TEB", "hStdOutput", 0);
2996 okChildInt("TEB", "hStdError", 0);
2998 DeleteFileA(resfile
);
3001 DeleteFileA(tempfile
);
3005 static void test_GetNumaProcessorNode(void)
3012 if (!pGetNumaProcessorNode
)
3014 win_skip("GetNumaProcessorNode is missing\n");
3019 for (i
= 0; i
< 256; i
++)
3021 SetLastError(0xdeadbeef);
3022 node
= (i
< si
.dwNumberOfProcessors
) ? 0xFF : 0xAA;
3023 ret
= pGetNumaProcessorNode(i
, &node
);
3024 if (i
< si
.dwNumberOfProcessors
)
3026 ok(ret
, "GetNumaProcessorNode returned FALSE for processor %d\n", i
);
3027 ok(node
!= 0xFF, "expected node != 0xFF, but got 0xFF\n");
3031 ok(!ret
, "GetNumaProcessorNode returned TRUE for processor %d\n", i
);
3032 ok(node
== 0xFF || broken(node
== 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node
);
3033 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3038 static void test_session_info(void)
3040 DWORD session_id
, active_session
;
3043 if (!pProcessIdToSessionId
)
3045 win_skip("ProcessIdToSessionId is missing\n");
3049 r
= pProcessIdToSessionId(GetCurrentProcessId(), &session_id
);
3050 ok(r
, "ProcessIdToSessionId failed: %u\n", GetLastError());
3051 trace("session_id = %x\n", session_id
);
3053 active_session
= pWTSGetActiveConsoleSessionId();
3054 trace("active_session = %x\n", active_session
);
3057 static void test_process_info(void)
3060 static const ULONG info_size
[] =
3062 sizeof(PROCESS_BASIC_INFORMATION
) /* ProcessBasicInformation */,
3063 sizeof(QUOTA_LIMITS
) /* ProcessQuotaLimits */,
3064 sizeof(IO_COUNTERS
) /* ProcessIoCounters */,
3065 sizeof(VM_COUNTERS
) /* ProcessVmCounters */,
3066 sizeof(KERNEL_USER_TIMES
) /* ProcessTimes */,
3067 sizeof(ULONG
) /* ProcessBasePriority */,
3068 sizeof(ULONG
) /* ProcessRaisePriority */,
3069 sizeof(HANDLE
) /* ProcessDebugPort */,
3070 sizeof(HANDLE
) /* ProcessExceptionPort */,
3071 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3072 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3073 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3074 sizeof(ULONG
) /* ProcessDefaultHardErrorMode */,
3075 0 /* ProcessIoPortHandlers: kernel-mode only */,
3076 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3077 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3078 sizeof(ULONG
) /* ProcessUserModeIOPL */,
3079 sizeof(BOOLEAN
) /* ProcessEnableAlignmentFaultFixup */,
3080 sizeof(PROCESS_PRIORITY_CLASS
) /* ProcessPriorityClass */,
3081 sizeof(ULONG
) /* ProcessWx86Information */,
3082 sizeof(ULONG
) /* ProcessHandleCount */,
3083 sizeof(ULONG_PTR
) /* ProcessAffinityMask */,
3084 sizeof(ULONG
) /* ProcessPriorityBoost */,
3085 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3086 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3087 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3088 sizeof(ULONG_PTR
) /* ProcessWow64Information */,
3089 sizeof(buf
) /* ProcessImageFileName */,
3090 sizeof(ULONG
) /* ProcessLUIDDeviceMapsEnabled */,
3091 sizeof(ULONG
) /* ProcessBreakOnTermination */,
3092 sizeof(HANDLE
) /* ProcessDebugObjectHandle */,
3093 sizeof(ULONG
) /* ProcessDebugFlags */,
3094 sizeof(buf
) /* ProcessHandleTracing */,
3095 sizeof(ULONG
) /* ProcessIoPriority */,
3096 sizeof(ULONG
) /* ProcessExecuteFlags */,
3097 0 /* FIXME: sizeof(?) ProcessTlsInformation */,
3098 0 /* FIXME: sizeof(?) ProcessCookie */,
3099 sizeof(SECTION_IMAGE_INFORMATION
) /* ProcessImageInformation */,
3100 0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */,
3101 sizeof(ULONG
) /* ProcessPagePriority */,
3102 40 /* ProcessInstrumentationCallback */,
3103 0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
3104 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
3105 sizeof(buf
) /* ProcessImageFileNameWin32 */,
3106 sizeof(HANDLE
) /* ProcessImageFileMapping */,
3107 0 /* FIXME: sizeof(PROCESS_AFFINITY_UPDATE_MODE) ProcessAffinityUpdateMode */,
3108 0 /* FIXME: sizeof(PROCESS_MEMORY_ALLOCATION_MODE) ProcessMemoryAllocationMode */,
3109 sizeof(USHORT
) /* ProcessGroupInformation */,
3110 sizeof(ULONG
) /* ProcessTokenVirtualizationEnabled */,
3111 sizeof(ULONG_PTR
) /* ProcessConsoleHostProcess */,
3112 0 /* FIXME: sizeof(PROCESS_WINDOW_INFORMATION) ProcessWindowInformation */,
3113 #if 0 /* FIXME: Add remaining classes */
3114 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION
) /* ProcessHandleInformation */,
3115 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION
) /* ProcessMitigationPolicy */,
3116 sizeof(ProcessDynamicFunctionTableInformation
) /* ProcessDynamicFunctionTableInformation */,
3117 sizeof(?) /* ProcessHandleCheckingMode */,
3118 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION
) /* ProcessKeepAliveCount */,
3119 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION
) /* ProcessRevokeFileHandles */,
3120 sizeof(PROCESS_WORKING_SET_CONTROL
) /* ProcessWorkingSetControl */,
3121 sizeof(?) /* ProcessHandleTable */,
3122 sizeof(?) /* ProcessCheckStackExtentsMode */,
3123 sizeof(buf
) /* ProcessCommandLineInformation */,
3124 sizeof(PS_PROTECTION
) /* ProcessProtectionInformation */,
3125 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO
) /* ProcessMemoryExhaustion */,
3126 sizeof(PROCESS_FAULT_INFORMATION
) /* ProcessFaultInformation */,
3127 sizeof(PROCESS_TELEMETRY_ID_INFORMATION
) /* ProcessTelemetryIdInformation */,
3128 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION
) /* ProcessCommitReleaseInformation */,
3129 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3130 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3131 0 /* ProcessReserved1Information */,
3132 0 /* ProcessReserved2Information */,
3133 sizeof(?) /* ProcessSubsystemProcess */,
3134 sizeof(PROCESS_JOB_MEMORY_INFO
) /* ProcessJobMemoryInformation */,
3138 ULONG i
, status
, ret_len
, size
;
3140 if (!pNtQueryInformationProcess
)
3142 win_skip("NtQueryInformationProcess is not available on this platform\n");
3146 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
3149 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
3153 for (i
= 0; i
< MaxProcessInfoClass
; i
++)
3155 size
= info_size
[i
];
3156 if (!size
) size
= sizeof(buf
);
3158 status
= pNtQueryInformationProcess(hproc
, i
, buf
, info_size
[i
], &ret_len
);
3159 if (status
== STATUS_NOT_IMPLEMENTED
) continue;
3160 if (status
== STATUS_INVALID_INFO_CLASS
) continue;
3161 if (status
== STATUS_INFO_LENGTH_MISMATCH
) continue;
3165 case ProcessBasicInformation
:
3166 case ProcessQuotaLimits
:
3168 case ProcessPriorityClass
:
3169 case ProcessPriorityBoost
:
3170 case ProcessLUIDDeviceMapsEnabled
:
3171 case 33 /* ProcessIoPriority */:
3172 case ProcessIoCounters
:
3173 case ProcessVmCounters
:
3174 case ProcessWow64Information
:
3175 case ProcessDefaultHardErrorMode
:
3176 case ProcessHandleCount
:
3177 case ProcessImageFileName
:
3178 case ProcessImageInformation
:
3179 case ProcessPagePriority
:
3180 case ProcessImageFileNameWin32
:
3181 ok(status
== STATUS_SUCCESS
, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3184 case ProcessAffinityMask
:
3185 case ProcessBreakOnTermination
:
3186 case ProcessGroupInformation
:
3187 case ProcessConsoleHostProcess
:
3188 ok(status
== STATUS_ACCESS_DENIED
/* before win8 */ || status
== STATUS_SUCCESS
/* win8 is less strict */,
3189 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3192 case ProcessDebugObjectHandle
:
3193 ok(status
== STATUS_ACCESS_DENIED
|| status
== STATUS_PORT_NOT_SET
,
3194 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3197 case ProcessExecuteFlags
:
3198 case ProcessDebugPort
:
3199 case ProcessDebugFlags
:
3202 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3206 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
3214 static void test_GetLogicalProcessorInformationEx(void)
3216 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*info
;
3220 if (!pGetLogicalProcessorInformationEx
)
3222 win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3226 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, NULL
);
3227 ok(!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "got %d, error %d\n", ret
, GetLastError());
3230 ret
= pGetLogicalProcessorInformationEx(RelationProcessorCore
, NULL
, &len
);
3231 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %d\n", ret
, GetLastError());
3232 ok(len
> 0, "got %u\n", len
);
3235 ret
= pGetLogicalProcessorInformationEx(RelationAll
, NULL
, &len
);
3236 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, error %d\n", ret
, GetLastError());
3237 ok(len
> 0, "got %u\n", len
);
3239 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
3240 ret
= pGetLogicalProcessorInformationEx(RelationAll
, info
, &len
);
3241 ok(ret
, "got %d, error %d\n", ret
, GetLastError());
3242 ok(info
->Size
> 0, "got %u\n", info
->Size
);
3243 HeapFree(GetProcessHeap(), 0, info
);
3246 static void test_largepages(void)
3250 if (!pGetLargePageMinimum
) {
3251 skip("No GetLargePageMinimum support.\n");
3254 size
= pGetLargePageMinimum();
3256 ok((size
== 0) || (size
== 2*1024*1024) || (size
== 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size
);
3259 struct proc_thread_attr
3266 struct _PROC_THREAD_ATTRIBUTE_LIST
3268 DWORD mask
; /* bitmask of items in list */
3269 DWORD size
; /* max number of items in list */
3270 DWORD count
; /* number of items in list */
3273 struct proc_thread_attr attrs
[10];
3276 static void test_ProcThreadAttributeList(void)
3279 SIZE_T size
, needed
;
3281 struct _PROC_THREAD_ATTRIBUTE_LIST list
, expect_list
;
3284 if (!pInitializeProcThreadAttributeList
)
3286 win_skip("No support for ProcThreadAttributeList\n");
3290 for (i
= 0; i
<= 10; i
++)
3292 needed
= FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST
, attrs
[i
]);
3293 ret
= pInitializeProcThreadAttributeList(NULL
, i
, 0, &size
);
3294 ok(!ret
, "got %d\n", ret
);
3295 if(i
>= 4 && GetLastError() == ERROR_INVALID_PARAMETER
) /* Vista only allows a maximium of 3 slots */
3297 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d\n", GetLastError());
3298 ok(size
== needed
, "%d: got %ld expect %ld\n", i
, size
, needed
);
3300 memset(&list
, 0xcc, sizeof(list
));
3301 ret
= pInitializeProcThreadAttributeList(&list
, i
, 0, &size
);
3302 ok(ret
, "got %d\n", ret
);
3303 ok(list
.mask
== 0, "%d: got %08x\n", i
, list
.mask
);
3304 ok(list
.size
== i
, "%d: got %08x\n", i
, list
.size
);
3305 ok(list
.count
== 0, "%d: got %08x\n", i
, list
.count
);
3306 ok(list
.unk
== 0, "%d: got %08lx\n", i
, list
.unk
);
3309 memset(handles
, 0, sizeof(handles
));
3310 memset(&expect_list
, 0xcc, sizeof(expect_list
));
3311 expect_list
.mask
= 0;
3312 expect_list
.size
= i
- 1;
3313 expect_list
.count
= 0;
3314 expect_list
.unk
= 0;
3316 ret
= pUpdateProcThreadAttribute(&list
, 0, 0xcafe, handles
, sizeof(PROCESSOR_NUMBER
), NULL
, NULL
);
3317 ok(!ret
, "got %d\n", ret
);
3318 ok(GetLastError() == ERROR_NOT_SUPPORTED
, "got %d\n", GetLastError());
3320 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]) / 2, NULL
, NULL
);
3321 ok(!ret
, "got %d\n", ret
);
3322 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %d\n", GetLastError());
3324 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]) * 2, NULL
, NULL
);
3325 ok(!ret
, "got %d\n", ret
);
3326 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %d\n", GetLastError());
3328 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]), NULL
, NULL
);
3329 ok(ret
, "got %d\n", ret
);
3331 expect_list
.mask
|= 1 << ProcThreadAttributeParentProcess
;
3332 expect_list
.attrs
[0].attr
= PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
;
3333 expect_list
.attrs
[0].size
= sizeof(handles
[0]);
3334 expect_list
.attrs
[0].value
= handles
;
3335 expect_list
.count
++;
3337 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
, handles
, sizeof(handles
[0]), NULL
, NULL
);
3338 ok(!ret
, "got %d\n", ret
);
3339 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS
, "got %d\n", GetLastError());
3341 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
) - 1, NULL
, NULL
);
3342 ok(!ret
, "got %d\n", ret
);
3343 ok(GetLastError() == ERROR_BAD_LENGTH
, "got %d\n", GetLastError());
3345 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
), NULL
, NULL
);
3346 ok(ret
, "got %d\n", ret
);
3348 expect_list
.mask
|= 1 << ProcThreadAttributeHandleList
;
3349 expect_list
.attrs
[1].attr
= PROC_THREAD_ATTRIBUTE_HANDLE_LIST
;
3350 expect_list
.attrs
[1].size
= sizeof(handles
);
3351 expect_list
.attrs
[1].value
= handles
;
3352 expect_list
.count
++;
3354 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST
, handles
, sizeof(handles
), NULL
, NULL
);
3355 ok(!ret
, "got %d\n", ret
);
3356 ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS
, "got %d\n", GetLastError());
3358 ret
= pUpdateProcThreadAttribute(&list
, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR
, handles
, sizeof(PROCESSOR_NUMBER
), NULL
, NULL
);
3359 ok(ret
|| (!ret
&& GetLastError() == ERROR_NOT_SUPPORTED
), "got %d gle %d\n", ret
, GetLastError());
3363 expect_list
.mask
|= 1 << ProcThreadAttributeIdealProcessor
;
3364 expect_list
.attrs
[2].attr
= PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR
;
3365 expect_list
.attrs
[2].size
= sizeof(PROCESSOR_NUMBER
);
3366 expect_list
.attrs
[2].value
= handles
;
3367 expect_list
.count
++;
3370 ok(!memcmp(&list
, &expect_list
, size
), "mismatch\n");
3372 pDeleteProcThreadAttributeList(&list
);
3375 static void test_GetActiveProcessorCount(void)
3379 if (!pGetActiveProcessorCount
)
3381 win_skip("GetActiveProcessorCount not available, skipping test\n");
3385 count
= pGetActiveProcessorCount(0);
3386 ok(count
, "GetActiveProcessorCount failed, error %u\n", GetLastError());
3388 /* Test would fail on systems with more than 6400 processors */
3389 SetLastError(0xdeadbeef);
3390 count
= pGetActiveProcessorCount(101);
3391 ok(count
== 0, "Expeced GetActiveProcessorCount to fail\n");
3392 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3399 ok(b
, "Basic init of CreateProcess test\n");
3404 if (!strcmp(myARGV
[2], "dump") && myARGC
>= 4)
3406 doChild(myARGV
[3], (myARGC
>= 5) ? myARGV
[4] : NULL
);
3409 else if (!strcmp(myARGV
[2], "wait"))
3412 ok(0, "Child process not killed\n");
3415 else if (!strcmp(myARGV
[2], "exit"))
3420 else if (!strcmp(myARGV
[2], "nested") && myARGC
>= 4)
3422 char buffer
[MAX_PATH
];
3423 STARTUPINFOA startup
;
3424 PROCESS_INFORMATION info
;
3426 memset(&startup
, 0, sizeof(startup
));
3427 startup
.cb
= sizeof(startup
);
3428 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
3429 startup
.wShowWindow
= SW_SHOWNORMAL
;
3431 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, myARGV
[3]);
3432 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess failed\n");
3433 CloseHandle(info
.hProcess
);
3434 CloseHandle(info
.hThread
);
3438 ok(0, "Unexpected command %s\n", myARGV
[2]);
3442 test_process_info();
3443 test_TerminateProcess();
3450 test_DebuggingFlag();
3454 test_GetProcessVersion();
3455 test_GetProcessImageFileNameA();
3456 test_QueryFullProcessImageNameA();
3457 test_QueryFullProcessImageNameW();
3459 test_IsWow64Process();
3461 test_RegistryQuota();
3462 test_DuplicateHandle();
3463 test_StartupNoConsole();
3464 test_DetachConsoleHandles();
3465 test_DetachStdHandles();
3466 test_GetNumaProcessorNode();
3467 test_session_info();
3468 test_GetLogicalProcessorInformationEx();
3469 test_GetActiveProcessorCount();
3471 test_ProcThreadAttributeList();
3473 /* things that can be tested:
3474 * lookup: check the way program to be executed is searched
3475 * handles: check the handle inheritance stuff (+sec options)
3476 * console: check if console creation parameters work
3479 if (!pCreateJobObjectW
)
3481 win_skip("No job object support\n");
3485 test_IsProcessInJob();
3486 test_TerminateJobObject();
3487 test_QueryInformationJobObject();
3488 test_CompletionPort();
3489 test_KillOnJobClose();
3490 test_WaitForJobObject();
3491 job
= test_AddSelfToJob();
3492 test_jobInheritance(job
);
3493 test_BreakawayOk(job
);