1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Unit test suite for process functions
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 2002 Eric Pouech
5c2c66affSColin Finck  * Copyright 2006 Dmitry Timoshkov
6*8a437ac5STimo Kreuzer  * Copyright 2014 Michael Müller
7c2c66affSColin Finck  *
8c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
9c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
10c2c66affSColin Finck  * License as published by the Free Software Foundation; either
11c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
12c2c66affSColin Finck  *
13c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
14c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16c2c66affSColin Finck  * Lesser General Public License for more details.
17c2c66affSColin Finck  *
18c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
19c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
20c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21c2c66affSColin Finck  */
22c2c66affSColin Finck 
23ed41a4deSAmine Khaldi #include <assert.h>
24ed41a4deSAmine Khaldi #include <stdarg.h>
25ed41a4deSAmine Khaldi #include <stdio.h>
26ed41a4deSAmine Khaldi #include <stdlib.h>
27ed41a4deSAmine Khaldi 
28ed41a4deSAmine Khaldi #include "ntstatus.h"
29ed41a4deSAmine Khaldi #define WIN32_NO_STATUS
30ed41a4deSAmine Khaldi #include "windef.h"
31ed41a4deSAmine Khaldi #include "winbase.h"
32ed41a4deSAmine Khaldi #include "winuser.h"
33ed41a4deSAmine Khaldi #include "wincon.h"
34ed41a4deSAmine Khaldi #include "winnls.h"
35ed41a4deSAmine Khaldi #include "winternl.h"
36ed41a4deSAmine Khaldi #include "tlhelp32.h"
37ed41a4deSAmine Khaldi 
38ed41a4deSAmine Khaldi #include "wine/test.h"
39ed41a4deSAmine Khaldi 
40ed41a4deSAmine Khaldi #include "winnt.h"
41c2c66affSColin Finck 
42c2c66affSColin Finck /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
43c2c66affSColin Finck #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
44c2c66affSColin Finck /* THREAD_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
45c2c66affSColin Finck #define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
46c2c66affSColin Finck 
47c2c66affSColin Finck #define expect_eq_d(expected, actual) \
48c2c66affSColin Finck     do { \
49c2c66affSColin Finck       int value = (actual); \
50c2c66affSColin Finck       ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
51c2c66affSColin Finck           (expected), value); \
52c2c66affSColin Finck     } while (0)
53c2c66affSColin Finck #define expect_eq_s(expected, actual) \
54c2c66affSColin Finck     do { \
55c2c66affSColin Finck       LPCSTR value = (actual); \
56c2c66affSColin Finck       ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
57c2c66affSColin Finck           expected, value); \
58c2c66affSColin Finck     } while (0)
59c2c66affSColin Finck #define expect_eq_ws_i(expected, actual) \
60c2c66affSColin Finck     do { \
61c2c66affSColin Finck       LPCWSTR value = (actual); \
62c2c66affSColin Finck       ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
63c2c66affSColin Finck           wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
64c2c66affSColin Finck     } while (0)
65c2c66affSColin Finck 
66c2c66affSColin Finck static HINSTANCE hkernel32, hntdll;
67c2c66affSColin Finck static void   (WINAPI *pGetNativeSystemInfo)(LPSYSTEM_INFO);
68c2c66affSColin Finck static BOOL   (WINAPI *pGetSystemRegistryQuota)(PDWORD, PDWORD);
69c2c66affSColin Finck static BOOL   (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
70c2c66affSColin Finck static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
71c2c66affSColin Finck static BOOL   (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
72c2c66affSColin Finck static BOOL   (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize);
73c2c66affSColin Finck static BOOL   (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize);
74c2c66affSColin Finck static DWORD  (WINAPI *pK32GetProcessImageFileNameA)(HANDLE,LPSTR,DWORD);
75c2c66affSColin Finck static HANDLE (WINAPI *pCreateJobObjectW)(LPSECURITY_ATTRIBUTES sa, LPCWSTR name);
76c2c66affSColin Finck static BOOL   (WINAPI *pAssignProcessToJobObject)(HANDLE job, HANDLE process);
77c2c66affSColin Finck static BOOL   (WINAPI *pIsProcessInJob)(HANDLE process, HANDLE job, PBOOL result);
78c2c66affSColin Finck static BOOL   (WINAPI *pTerminateJobObject)(HANDLE job, UINT exit_code);
79c2c66affSColin Finck static BOOL   (WINAPI *pQueryInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len, LPDWORD ret_len);
80c2c66affSColin Finck static BOOL   (WINAPI *pSetInformationJobObject)(HANDLE job, JOBOBJECTINFOCLASS class, LPVOID info, DWORD len);
81c2c66affSColin Finck static HANDLE (WINAPI *pCreateIoCompletionPort)(HANDLE file, HANDLE existing_port, ULONG_PTR key, DWORD threads);
82c2c66affSColin Finck static BOOL   (WINAPI *pGetNumaProcessorNode)(UCHAR, PUCHAR);
83c2c66affSColin Finck static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
84c2c66affSColin Finck static BOOL   (WINAPI *pProcessIdToSessionId)(DWORD,DWORD*);
85c2c66affSColin Finck static DWORD  (WINAPI *pWTSGetActiveConsoleSessionId)(void);
86c2c66affSColin Finck static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD);
87c2c66affSColin Finck static BOOL   (WINAPI *pProcess32First)(HANDLE, PROCESSENTRY32*);
88c2c66affSColin Finck static BOOL   (WINAPI *pProcess32Next)(HANDLE, PROCESSENTRY32*);
89c2c66affSColin Finck static BOOL   (WINAPI *pThread32First)(HANDLE, THREADENTRY32*);
90c2c66affSColin Finck static BOOL   (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*);
91c2c66affSColin Finck static BOOL   (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
92c2c66affSColin Finck static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
93c2c66affSColin Finck static BOOL   (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
94c2c66affSColin Finck static BOOL   (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
95c2c66affSColin Finck static void   (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
96c2c66affSColin Finck static DWORD  (WINAPI *pGetActiveProcessorCount)(WORD);
97c2c66affSColin Finck 
98c2c66affSColin Finck /* ############################### */
99c2c66affSColin Finck static char     base[MAX_PATH];
100c2c66affSColin Finck static char     selfname[MAX_PATH];
101c2c66affSColin Finck static char*    exename;
102c2c66affSColin Finck static char     resfile[MAX_PATH];
103c2c66affSColin Finck 
104c2c66affSColin Finck static int      myARGC;
105c2c66affSColin Finck static char**   myARGV;
106c2c66affSColin Finck 
107c2c66affSColin Finck /* As some environment variables get very long on Unix, we only test for
108c2c66affSColin Finck  * the first 127 bytes.
109c2c66affSColin Finck  * Note that increasing this value past 256 may exceed the buffer size
110c2c66affSColin Finck  * limitations of the *Profile functions (at least on Wine).
111c2c66affSColin Finck  */
112c2c66affSColin Finck #define MAX_LISTED_ENV_VAR      128
113c2c66affSColin Finck 
114c2c66affSColin Finck /* ---------------- portable memory allocation thingie */
115c2c66affSColin Finck 
116c2c66affSColin Finck static char     memory[1024*256];
117c2c66affSColin Finck static char*    memory_index = memory;
118c2c66affSColin Finck 
grab_memory(size_t len)119c2c66affSColin Finck static char*    grab_memory(size_t len)
120c2c66affSColin Finck {
121c2c66affSColin Finck     char*       ret = memory_index;
122c2c66affSColin Finck     /* align on dword */
123c2c66affSColin Finck     len = (len + 3) & ~3;
124c2c66affSColin Finck     memory_index += len;
125c2c66affSColin Finck     assert(memory_index <= memory + sizeof(memory));
126c2c66affSColin Finck     return ret;
127c2c66affSColin Finck }
128c2c66affSColin Finck 
release_memory(void)129c2c66affSColin Finck static void     release_memory(void)
130c2c66affSColin Finck {
131c2c66affSColin Finck     memory_index = memory;
132c2c66affSColin Finck }
133c2c66affSColin Finck 
134c2c66affSColin Finck /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
135c2c66affSColin Finck 
encodeA(const char * str)136c2c66affSColin Finck static const char* encodeA(const char* str)
137c2c66affSColin Finck {
138c2c66affSColin Finck     char*       ptr;
139c2c66affSColin Finck     size_t      len,i;
140c2c66affSColin Finck 
141c2c66affSColin Finck     if (!str) return "";
142c2c66affSColin Finck     len = strlen(str) + 1;
143c2c66affSColin Finck     ptr = grab_memory(len * 2 + 1);
144c2c66affSColin Finck     for (i = 0; i < len; i++)
145c2c66affSColin Finck         sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
146c2c66affSColin Finck     ptr[2 * len] = '\0';
147c2c66affSColin Finck     return ptr;
148c2c66affSColin Finck }
149c2c66affSColin Finck 
encodeW(const WCHAR * str)150c2c66affSColin Finck static const char* encodeW(const WCHAR* str)
151c2c66affSColin Finck {
152c2c66affSColin Finck     char*       ptr;
153c2c66affSColin Finck     size_t      len,i;
154c2c66affSColin Finck 
155c2c66affSColin Finck     if (!str) return "";
156c2c66affSColin Finck     len = lstrlenW(str) + 1;
157c2c66affSColin Finck     ptr = grab_memory(len * 4 + 1);
158c2c66affSColin Finck     assert(ptr);
159c2c66affSColin Finck     for (i = 0; i < len; i++)
160c2c66affSColin Finck         sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
161c2c66affSColin Finck     ptr[4 * len] = '\0';
162c2c66affSColin Finck     return ptr;
163c2c66affSColin Finck }
164c2c66affSColin Finck 
decode_char(char c)165c2c66affSColin Finck static unsigned decode_char(char c)
166c2c66affSColin Finck {
167c2c66affSColin Finck     if (c >= '0' && c <= '9') return c - '0';
168c2c66affSColin Finck     if (c >= 'a' && c <= 'f') return c - 'a' + 10;
169c2c66affSColin Finck     assert(c >= 'A' && c <= 'F');
170c2c66affSColin Finck     return c - 'A' + 10;
171c2c66affSColin Finck }
172c2c66affSColin Finck 
decodeA(const char * str)173c2c66affSColin Finck static char*    decodeA(const char* str)
174c2c66affSColin Finck {
175c2c66affSColin Finck     char*       ptr;
176c2c66affSColin Finck     size_t      len,i;
177c2c66affSColin Finck 
178c2c66affSColin Finck     len = strlen(str) / 2;
179c2c66affSColin Finck     if (!len--) return NULL;
180c2c66affSColin Finck     ptr = grab_memory(len + 1);
181c2c66affSColin Finck     for (i = 0; i < len; i++)
182c2c66affSColin Finck         ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
183c2c66affSColin Finck     ptr[len] = '\0';
184c2c66affSColin Finck     return ptr;
185c2c66affSColin Finck }
186c2c66affSColin Finck 
187c2c66affSColin Finck /* This will be needed to decode Unicode strings saved by the child process
188c2c66affSColin Finck  * when we test Unicode functions.
189c2c66affSColin Finck  */
decodeW(const char * str)190c2c66affSColin Finck static WCHAR*   decodeW(const char* str)
191c2c66affSColin Finck {
192c2c66affSColin Finck     size_t      len;
193c2c66affSColin Finck     WCHAR*      ptr;
194c2c66affSColin Finck     int         i;
195c2c66affSColin Finck 
196c2c66affSColin Finck     len = strlen(str) / 4;
197c2c66affSColin Finck     if (!len--) return NULL;
198c2c66affSColin Finck     ptr = (WCHAR*)grab_memory(len * 2 + 1);
199c2c66affSColin Finck     for (i = 0; i < len; i++)
200c2c66affSColin Finck         ptr[i] = (decode_char(str[4 * i]) << 12) |
201c2c66affSColin Finck             (decode_char(str[4 * i + 1]) << 8) |
202c2c66affSColin Finck             (decode_char(str[4 * i + 2]) << 4) |
203c2c66affSColin Finck             (decode_char(str[4 * i + 3]) << 0);
204c2c66affSColin Finck     ptr[len] = '\0';
205c2c66affSColin Finck     return ptr;
206c2c66affSColin Finck }
207c2c66affSColin Finck 
208c2c66affSColin Finck /******************************************************************
209c2c66affSColin Finck  *		init
210c2c66affSColin Finck  *
211c2c66affSColin Finck  * generates basic information like:
212c2c66affSColin Finck  *      base:           absolute path to curr dir
213c2c66affSColin Finck  *      selfname:       the way to reinvoke ourselves
214c2c66affSColin Finck  *      exename:        executable without the path
215c2c66affSColin Finck  * function-pointers, which are not implemented in all windows versions
216c2c66affSColin Finck  */
init(void)217c2c66affSColin Finck static BOOL init(void)
218c2c66affSColin Finck {
219c2c66affSColin Finck     char *p;
220c2c66affSColin Finck 
221c2c66affSColin Finck     myARGC = winetest_get_mainargs( &myARGV );
222c2c66affSColin Finck     if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
223c2c66affSColin Finck     strcpy(selfname, myARGV[0]);
224c2c66affSColin Finck 
225c2c66affSColin Finck     /* Strip the path of selfname */
226c2c66affSColin Finck     if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1;
227c2c66affSColin Finck     else exename = selfname;
228c2c66affSColin Finck 
229c2c66affSColin Finck     if ((p = strrchr(exename, '/')) != NULL) exename = p + 1;
230c2c66affSColin Finck 
231c2c66affSColin Finck     hkernel32 = GetModuleHandleA("kernel32");
232c2c66affSColin Finck     hntdll    = GetModuleHandleA("ntdll.dll");
233c2c66affSColin Finck 
234c2c66affSColin Finck     pNtQueryInformationProcess = (void *)GetProcAddress(hntdll, "NtQueryInformationProcess");
235c2c66affSColin Finck 
236c2c66affSColin Finck     pGetNativeSystemInfo = (void *) GetProcAddress(hkernel32, "GetNativeSystemInfo");
237c2c66affSColin Finck     pGetSystemRegistryQuota = (void *) GetProcAddress(hkernel32, "GetSystemRegistryQuota");
238c2c66affSColin Finck     pIsWow64Process = (void *) GetProcAddress(hkernel32, "IsWow64Process");
239c2c66affSColin Finck     pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
240c2c66affSColin Finck     pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
241c2c66affSColin Finck     pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA");
242c2c66affSColin Finck     pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW");
243c2c66affSColin Finck     pK32GetProcessImageFileNameA = (void *) GetProcAddress(hkernel32, "K32GetProcessImageFileNameA");
244c2c66affSColin Finck     pCreateJobObjectW = (void *)GetProcAddress(hkernel32, "CreateJobObjectW");
245c2c66affSColin Finck     pAssignProcessToJobObject = (void *)GetProcAddress(hkernel32, "AssignProcessToJobObject");
246c2c66affSColin Finck     pIsProcessInJob = (void *)GetProcAddress(hkernel32, "IsProcessInJob");
247c2c66affSColin Finck     pTerminateJobObject = (void *)GetProcAddress(hkernel32, "TerminateJobObject");
248c2c66affSColin Finck     pQueryInformationJobObject = (void *)GetProcAddress(hkernel32, "QueryInformationJobObject");
249c2c66affSColin Finck     pSetInformationJobObject = (void *)GetProcAddress(hkernel32, "SetInformationJobObject");
250c2c66affSColin Finck     pCreateIoCompletionPort = (void *)GetProcAddress(hkernel32, "CreateIoCompletionPort");
251c2c66affSColin Finck     pGetNumaProcessorNode = (void *)GetProcAddress(hkernel32, "GetNumaProcessorNode");
252c2c66affSColin Finck     pProcessIdToSessionId = (void *)GetProcAddress(hkernel32, "ProcessIdToSessionId");
253c2c66affSColin Finck     pWTSGetActiveConsoleSessionId = (void *)GetProcAddress(hkernel32, "WTSGetActiveConsoleSessionId");
254c2c66affSColin Finck     pCreateToolhelp32Snapshot = (void *)GetProcAddress(hkernel32, "CreateToolhelp32Snapshot");
255c2c66affSColin Finck     pProcess32First = (void *)GetProcAddress(hkernel32, "Process32First");
256c2c66affSColin Finck     pProcess32Next = (void *)GetProcAddress(hkernel32, "Process32Next");
257c2c66affSColin Finck     pThread32First = (void *)GetProcAddress(hkernel32, "Thread32First");
258c2c66affSColin Finck     pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next");
259c2c66affSColin Finck     pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
260c2c66affSColin Finck     pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum");
261c2c66affSColin Finck     pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
262c2c66affSColin Finck     pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
263c2c66affSColin Finck     pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
264c2c66affSColin Finck     pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount");
265c2c66affSColin Finck 
266c2c66affSColin Finck     return TRUE;
267c2c66affSColin Finck }
268c2c66affSColin Finck 
269c2c66affSColin Finck /******************************************************************
270c2c66affSColin Finck  *		get_file_name
271c2c66affSColin Finck  *
272c2c66affSColin Finck  * generates an absolute file_name for temporary file
273c2c66affSColin Finck  *
274c2c66affSColin Finck  */
get_file_name(char * buf)275c2c66affSColin Finck static void     get_file_name(char* buf)
276c2c66affSColin Finck {
277c2c66affSColin Finck     char        path[MAX_PATH];
278c2c66affSColin Finck 
279c2c66affSColin Finck     buf[0] = '\0';
280c2c66affSColin Finck     GetTempPathA(sizeof(path), path);
281c2c66affSColin Finck     GetTempFileNameA(path, "wt", 0, buf);
282c2c66affSColin Finck }
283c2c66affSColin Finck 
284c2c66affSColin Finck /******************************************************************
285c2c66affSColin Finck  *		static void     childPrintf
286c2c66affSColin Finck  *
287c2c66affSColin Finck  */
childPrintf(HANDLE h,const char * fmt,...)288c2c66affSColin Finck static void WINETEST_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fmt, ...)
289c2c66affSColin Finck {
290c2c66affSColin Finck     va_list     valist;
291c2c66affSColin Finck     char        buffer[1024+4*MAX_LISTED_ENV_VAR];
292c2c66affSColin Finck     DWORD       w;
293c2c66affSColin Finck 
294c2c66affSColin Finck     va_start(valist, fmt);
295c2c66affSColin Finck     vsprintf(buffer, fmt, valist);
296c2c66affSColin Finck     va_end(valist);
297c2c66affSColin Finck     WriteFile(h, buffer, strlen(buffer), &w, NULL);
298c2c66affSColin Finck }
299c2c66affSColin Finck 
300c2c66affSColin Finck 
301c2c66affSColin Finck /******************************************************************
302c2c66affSColin Finck  *		doChild
303c2c66affSColin Finck  *
304c2c66affSColin Finck  * output most of the information in the child process
305c2c66affSColin Finck  */
doChild(const char * file,const char * option)306c2c66affSColin Finck static void     doChild(const char* file, const char* option)
307c2c66affSColin Finck {
308c2c66affSColin Finck     RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
309c2c66affSColin Finck     STARTUPINFOA        siA;
310c2c66affSColin Finck     STARTUPINFOW        siW;
311c2c66affSColin Finck     int                 i;
312c2c66affSColin Finck     char                *ptrA, *ptrA_save;
313c2c66affSColin Finck     WCHAR               *ptrW, *ptrW_save;
314c2c66affSColin Finck     char                bufA[MAX_PATH];
315c2c66affSColin Finck     WCHAR               bufW[MAX_PATH];
316c2c66affSColin Finck     HANDLE              hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
317c2c66affSColin Finck     HANDLE              snapshot;
318c2c66affSColin Finck     PROCESSENTRY32      pe;
319c2c66affSColin Finck     BOOL ret;
320c2c66affSColin Finck 
321c2c66affSColin Finck     if (hFile == INVALID_HANDLE_VALUE) return;
322c2c66affSColin Finck 
323c2c66affSColin Finck     /* output of startup info (Ansi) */
324c2c66affSColin Finck     GetStartupInfoA(&siA);
325c2c66affSColin Finck     childPrintf(hFile,
326c2c66affSColin Finck                 "[StartupInfoA]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
327c2c66affSColin Finck                 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
328c2c66affSColin Finck                 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
329c2c66affSColin Finck                 "dwFlags=%u\nwShowWindow=%u\n"
330c2c66affSColin Finck                 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
331c2c66affSColin Finck                 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
332c2c66affSColin Finck                 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize,
333c2c66affSColin Finck                 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute,
334c2c66affSColin Finck                 siA.dwFlags, siA.wShowWindow,
335c2c66affSColin Finck                 (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError);
336c2c66affSColin Finck 
337c2c66affSColin Finck     /* check the console handles in the TEB */
338c2c66affSColin Finck     childPrintf(hFile, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
339c2c66affSColin Finck                 (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput,
340c2c66affSColin Finck                 (DWORD_PTR)params->hStdError);
341c2c66affSColin Finck 
342c2c66affSColin Finck     /* since GetStartupInfoW is only implemented in win2k,
343c2c66affSColin Finck      * zero out before calling so we can notice the difference
344c2c66affSColin Finck      */
345c2c66affSColin Finck     memset(&siW, 0, sizeof(siW));
346c2c66affSColin Finck     GetStartupInfoW(&siW);
347c2c66affSColin Finck     childPrintf(hFile,
348c2c66affSColin Finck                 "[StartupInfoW]\ncb=%08u\nlpDesktop=%s\nlpTitle=%s\n"
349c2c66affSColin Finck                 "dwX=%u\ndwY=%u\ndwXSize=%u\ndwYSize=%u\n"
350c2c66affSColin Finck                 "dwXCountChars=%u\ndwYCountChars=%u\ndwFillAttribute=%u\n"
351c2c66affSColin Finck                 "dwFlags=%u\nwShowWindow=%u\n"
352c2c66affSColin Finck                 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
353c2c66affSColin Finck                 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
354c2c66affSColin Finck                 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize,
355c2c66affSColin Finck                 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute,
356c2c66affSColin Finck                 siW.dwFlags, siW.wShowWindow,
357c2c66affSColin Finck                 (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError);
358c2c66affSColin Finck 
359c2c66affSColin Finck     /* Arguments */
360c2c66affSColin Finck     childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
361c2c66affSColin Finck     for (i = 0; i < myARGC; i++)
362c2c66affSColin Finck     {
363c2c66affSColin Finck         childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
364c2c66affSColin Finck     }
365c2c66affSColin Finck     childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
366c2c66affSColin Finck     childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
367c2c66affSColin Finck 
368c2c66affSColin Finck     /* output toolhelp information */
369c2c66affSColin Finck     snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
370c2c66affSColin Finck     ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
371c2c66affSColin Finck     memset(&pe, 0, sizeof(pe));
372c2c66affSColin Finck     pe.dwSize = sizeof(pe);
373c2c66affSColin Finck     if (pProcess32First(snapshot, &pe))
374c2c66affSColin Finck     {
375c2c66affSColin Finck         while (pe.th32ProcessID != GetCurrentProcessId())
376c2c66affSColin Finck             if (!pProcess32Next(snapshot, &pe)) break;
377c2c66affSColin Finck     }
378c2c66affSColin Finck     CloseHandle(snapshot);
379c2c66affSColin Finck     ok(pe.th32ProcessID == GetCurrentProcessId(), "failed to find current process in snapshot\n");
380c2c66affSColin Finck     childPrintf(hFile,
381c2c66affSColin Finck                 "[Toolhelp]\ncntUsage=%u\nth32DefaultHeapID=%lu\n"
382c2c66affSColin Finck                 "th32ModuleID=%u\ncntThreads=%u\nth32ParentProcessID=%u\n"
383c2c66affSColin Finck                 "pcPriClassBase=%u\ndwFlags=%u\nszExeFile=%s\n\n",
384c2c66affSColin Finck                 pe.cntUsage, pe.th32DefaultHeapID, pe.th32ModuleID,
385c2c66affSColin Finck                 pe.cntThreads, pe.th32ParentProcessID, pe.pcPriClassBase,
386c2c66affSColin Finck                 pe.dwFlags, encodeA(pe.szExeFile));
387c2c66affSColin Finck 
388c2c66affSColin Finck     /* output of environment (Ansi) */
389c2c66affSColin Finck     ptrA_save = ptrA = GetEnvironmentStringsA();
390c2c66affSColin Finck     if (ptrA)
391c2c66affSColin Finck     {
392c2c66affSColin Finck         char    env_var[MAX_LISTED_ENV_VAR];
393c2c66affSColin Finck 
394c2c66affSColin Finck         childPrintf(hFile, "[EnvironmentA]\n");
395c2c66affSColin Finck         i = 0;
396c2c66affSColin Finck         while (*ptrA)
397c2c66affSColin Finck         {
398c2c66affSColin Finck             lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR);
399c2c66affSColin Finck             childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
400c2c66affSColin Finck             i++;
401c2c66affSColin Finck             ptrA += strlen(ptrA) + 1;
402c2c66affSColin Finck         }
403c2c66affSColin Finck         childPrintf(hFile, "len=%d\n\n", i);
404c2c66affSColin Finck         FreeEnvironmentStringsA(ptrA_save);
405c2c66affSColin Finck     }
406c2c66affSColin Finck 
407c2c66affSColin Finck     /* output of environment (Unicode) */
408c2c66affSColin Finck     ptrW_save = ptrW = GetEnvironmentStringsW();
409c2c66affSColin Finck     if (ptrW)
410c2c66affSColin Finck     {
411c2c66affSColin Finck         WCHAR   env_var[MAX_LISTED_ENV_VAR];
412c2c66affSColin Finck 
413c2c66affSColin Finck         childPrintf(hFile, "[EnvironmentW]\n");
414c2c66affSColin Finck         i = 0;
415c2c66affSColin Finck         while (*ptrW)
416c2c66affSColin Finck         {
417c2c66affSColin Finck             lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1);
418c2c66affSColin Finck             env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
419c2c66affSColin Finck             childPrintf(hFile, "env%d=%s\n", i, encodeW(env_var));
420c2c66affSColin Finck             i++;
421c2c66affSColin Finck             ptrW += lstrlenW(ptrW) + 1;
422c2c66affSColin Finck         }
423c2c66affSColin Finck         childPrintf(hFile, "len=%d\n\n", i);
424c2c66affSColin Finck         FreeEnvironmentStringsW(ptrW_save);
425c2c66affSColin Finck     }
426c2c66affSColin Finck 
427c2c66affSColin Finck     childPrintf(hFile, "[Misc]\n");
428c2c66affSColin Finck     if (GetCurrentDirectoryA(sizeof(bufA), bufA))
429c2c66affSColin Finck         childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
430c2c66affSColin Finck     if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW))
431c2c66affSColin Finck         childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
432c2c66affSColin Finck     childPrintf(hFile, "\n");
433c2c66affSColin Finck 
434c2c66affSColin Finck     if (option && strcmp(option, "console") == 0)
435c2c66affSColin Finck     {
436c2c66affSColin Finck         CONSOLE_SCREEN_BUFFER_INFO	sbi;
437c2c66affSColin Finck         HANDLE hConIn  = GetStdHandle(STD_INPUT_HANDLE);
438c2c66affSColin Finck         HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
439c2c66affSColin Finck         DWORD modeIn, modeOut;
440c2c66affSColin Finck 
441c2c66affSColin Finck         childPrintf(hFile, "[Console]\n");
442c2c66affSColin Finck         if (GetConsoleScreenBufferInfo(hConOut, &sbi))
443c2c66affSColin Finck         {
444c2c66affSColin Finck             childPrintf(hFile, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
445c2c66affSColin Finck                         sbi.dwSize.X, sbi.dwSize.Y, sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y, sbi.wAttributes);
446c2c66affSColin Finck             childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
447c2c66affSColin Finck                         sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom);
448c2c66affSColin Finck             childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n",
449c2c66affSColin Finck                         sbi.dwMaximumWindowSize.X, sbi.dwMaximumWindowSize.Y);
450c2c66affSColin Finck         }
451c2c66affSColin Finck         childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
452c2c66affSColin Finck                     GetConsoleCP(), GetConsoleOutputCP());
453c2c66affSColin Finck         if (GetConsoleMode(hConIn, &modeIn))
454c2c66affSColin Finck             childPrintf(hFile, "InputMode=%u\n", modeIn);
455c2c66affSColin Finck         if (GetConsoleMode(hConOut, &modeOut))
456c2c66affSColin Finck             childPrintf(hFile, "OutputMode=%u\n", modeOut);
457c2c66affSColin Finck 
458c2c66affSColin Finck         /* now that we have written all relevant information, let's change it */
459c2c66affSColin Finck         SetLastError(0xdeadbeef);
460c2c66affSColin Finck         ret = SetConsoleCP(1252);
461c2c66affSColin Finck         if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
462c2c66affSColin Finck         {
463c2c66affSColin Finck             win_skip("Setting the codepage is not implemented\n");
464c2c66affSColin Finck         }
465c2c66affSColin Finck         else
466c2c66affSColin Finck         {
467c2c66affSColin Finck             ok(ret, "Setting CP\n");
468c2c66affSColin Finck             ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
469c2c66affSColin Finck         }
470c2c66affSColin Finck 
471c2c66affSColin Finck         ret = SetConsoleMode(hConIn, modeIn ^ 1);
472c2c66affSColin Finck         ok( ret, "Setting mode (%d)\n", GetLastError());
473c2c66affSColin Finck         ret = SetConsoleMode(hConOut, modeOut ^ 1);
474c2c66affSColin Finck         ok( ret, "Setting mode (%d)\n", GetLastError());
475c2c66affSColin Finck         sbi.dwCursorPosition.X ^= 1;
476c2c66affSColin Finck         sbi.dwCursorPosition.Y ^= 1;
477c2c66affSColin Finck         ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition);
478c2c66affSColin Finck         ok( ret, "Setting cursor position (%d)\n", GetLastError());
479c2c66affSColin Finck     }
480c2c66affSColin Finck     if (option && strcmp(option, "stdhandle") == 0)
481c2c66affSColin Finck     {
482c2c66affSColin Finck         HANDLE hStdIn  = GetStdHandle(STD_INPUT_HANDLE);
483c2c66affSColin Finck         HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
484c2c66affSColin Finck 
485c2c66affSColin Finck         if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE)
486c2c66affSColin Finck         {
487c2c66affSColin Finck             char buf[1024];
488c2c66affSColin Finck             DWORD r, w;
489c2c66affSColin Finck 
490c2c66affSColin Finck             ok(ReadFile(hStdIn, buf, sizeof(buf), &r, NULL) && r > 0, "Reading message from input pipe\n");
491c2c66affSColin Finck             childPrintf(hFile, "[StdHandle]\nmsg=%s\n\n", encodeA(buf));
492c2c66affSColin Finck             ok(WriteFile(hStdOut, buf, r, &w, NULL) && w == r, "Writing message to output pipe\n");
493c2c66affSColin Finck         }
494c2c66affSColin Finck     }
495c2c66affSColin Finck 
496c2c66affSColin Finck     if (option && strcmp(option, "exit_code") == 0)
497c2c66affSColin Finck     {
498c2c66affSColin Finck         childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123);
499c2c66affSColin Finck         CloseHandle(hFile);
500c2c66affSColin Finck         ExitProcess(123);
501c2c66affSColin Finck     }
502c2c66affSColin Finck 
503c2c66affSColin Finck     CloseHandle(hFile);
504c2c66affSColin Finck }
505c2c66affSColin Finck 
getChildString(const char * sect,const char * key)506c2c66affSColin Finck static char* getChildString(const char* sect, const char* key)
507c2c66affSColin Finck {
508c2c66affSColin Finck     char        buf[1024+4*MAX_LISTED_ENV_VAR];
509c2c66affSColin Finck     char*       ret;
510c2c66affSColin Finck 
511c2c66affSColin Finck     GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
512c2c66affSColin Finck     if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
513c2c66affSColin Finck     assert(!(strlen(buf) & 1));
514c2c66affSColin Finck     ret = decodeA(buf);
515c2c66affSColin Finck     return ret;
516c2c66affSColin Finck }
517c2c66affSColin Finck 
getChildStringW(const char * sect,const char * key)518c2c66affSColin Finck static WCHAR* getChildStringW(const char* sect, const char* key)
519c2c66affSColin Finck {
520c2c66affSColin Finck     char        buf[1024+4*MAX_LISTED_ENV_VAR];
521c2c66affSColin Finck     WCHAR*       ret;
522c2c66affSColin Finck 
523c2c66affSColin Finck     GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
524c2c66affSColin Finck     if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
525c2c66affSColin Finck     assert(!(strlen(buf) & 1));
526c2c66affSColin Finck     ret = decodeW(buf);
527c2c66affSColin Finck     return ret;
528c2c66affSColin Finck }
529c2c66affSColin Finck 
530c2c66affSColin Finck /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
531c2c66affSColin Finck  * others... (windows uses stricmp while Un*x uses strcasecmp...)
532c2c66affSColin Finck  */
wtstrcasecmp(const char * p1,const char * p2)533c2c66affSColin Finck static int wtstrcasecmp(const char* p1, const char* p2)
534c2c66affSColin Finck {
535c2c66affSColin Finck     char c1, c2;
536c2c66affSColin Finck 
537c2c66affSColin Finck     c1 = c2 = '@';
538c2c66affSColin Finck     while (c1 == c2 && c1)
539c2c66affSColin Finck     {
540c2c66affSColin Finck         c1 = *p1++; c2 = *p2++;
541c2c66affSColin Finck         if (c1 != c2)
542c2c66affSColin Finck         {
543c2c66affSColin Finck             c1 = toupper(c1); c2 = toupper(c2);
544c2c66affSColin Finck         }
545c2c66affSColin Finck     }
546c2c66affSColin Finck     return c1 - c2;
547c2c66affSColin Finck }
548c2c66affSColin Finck 
strCmp(const char * s1,const char * s2,BOOL sensitive)549c2c66affSColin Finck static int strCmp(const char* s1, const char* s2, BOOL sensitive)
550c2c66affSColin Finck {
551c2c66affSColin Finck     if (!s1 && !s2) return 0;
552c2c66affSColin Finck     if (!s2) return -1;
553c2c66affSColin Finck     if (!s1) return 1;
554c2c66affSColin Finck     return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2);
555c2c66affSColin Finck }
556c2c66affSColin Finck 
ok_child_string(int line,const char * sect,const char * key,const char * expect,int sensitive)557c2c66affSColin Finck static void ok_child_string( int line, const char *sect, const char *key,
558c2c66affSColin Finck                              const char *expect, int sensitive )
559c2c66affSColin Finck {
560c2c66affSColin Finck     char* result = getChildString( sect, key );
561c2c66affSColin Finck     ok_(__FILE__, line)( strCmp(result, expect, sensitive) == 0, "%s:%s expected '%s', got '%s'\n",
562c2c66affSColin Finck                          sect, key, expect ? expect : "(null)", result );
563c2c66affSColin Finck }
564c2c66affSColin Finck 
ok_child_stringWA(int line,const char * sect,const char * key,const char * expect,int sensitive)565c2c66affSColin Finck static void ok_child_stringWA( int line, const char *sect, const char *key,
566c2c66affSColin Finck                              const char *expect, int sensitive )
567c2c66affSColin Finck {
568c2c66affSColin Finck     WCHAR* expectW;
569c2c66affSColin Finck     CHAR* resultA;
570c2c66affSColin Finck     DWORD len;
571c2c66affSColin Finck     WCHAR* result = getChildStringW( sect, key );
572c2c66affSColin Finck 
573c2c66affSColin Finck     len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0);
574c2c66affSColin Finck     expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
575c2c66affSColin Finck     MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len);
576c2c66affSColin Finck 
577c2c66affSColin Finck     len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL);
578c2c66affSColin Finck     resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR));
579c2c66affSColin Finck     WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL);
580c2c66affSColin Finck 
581c2c66affSColin Finck     if (sensitive)
582c2c66affSColin Finck         ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
583c2c66affSColin Finck                          sect, key, expect ? expect : "(null)", resultA );
584c2c66affSColin Finck     else
585c2c66affSColin Finck         ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
586c2c66affSColin Finck                          sect, key, expect ? expect : "(null)", resultA );
587c2c66affSColin Finck     HeapFree(GetProcessHeap(),0,expectW);
588c2c66affSColin Finck     HeapFree(GetProcessHeap(),0,resultA);
589c2c66affSColin Finck }
590c2c66affSColin Finck 
ok_child_int(int line,const char * sect,const char * key,UINT expect)591c2c66affSColin Finck static void ok_child_int( int line, const char *sect, const char *key, UINT expect )
592c2c66affSColin Finck {
593c2c66affSColin Finck     UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile );
594c2c66affSColin Finck     ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result );
595c2c66affSColin Finck }
596c2c66affSColin Finck 
597c2c66affSColin Finck #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
598c2c66affSColin Finck #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
599c2c66affSColin Finck #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
600c2c66affSColin Finck #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect))
601c2c66affSColin Finck 
test_Startup(void)602c2c66affSColin Finck static void test_Startup(void)
603c2c66affSColin Finck {
604c2c66affSColin Finck     char                buffer[MAX_PATH];
605c2c66affSColin Finck     PROCESS_INFORMATION	info;
606c2c66affSColin Finck     STARTUPINFOA	startup,si;
607c2c66affSColin Finck     char *result;
608c2c66affSColin Finck     static CHAR title[]   = "I'm the title string",
609c2c66affSColin Finck                 desktop[] = "winsta0\\default",
610c2c66affSColin Finck                 empty[]   = "";
611c2c66affSColin Finck 
612c2c66affSColin Finck     /* let's start simplistic */
613c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
614c2c66affSColin Finck     startup.cb = sizeof(startup);
615c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
616c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
617c2c66affSColin Finck 
618c2c66affSColin Finck     get_file_name(resfile);
619c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
620c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
621c2c66affSColin Finck     /* wait for child to terminate */
622c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
623c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
624c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
6259ac94af4SThomas Faber     CloseHandle(info.hThread);
6269ac94af4SThomas Faber     CloseHandle(info.hProcess);
627c2c66affSColin Finck 
628c2c66affSColin Finck     GetStartupInfoA(&si);
629c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
630c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
631c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
632c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
633c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
634c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
635c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
636c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
637c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
638c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
639c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
640c2c66affSColin Finck     release_memory();
641c2c66affSColin Finck     DeleteFileA(resfile);
642c2c66affSColin Finck 
643c2c66affSColin Finck     /* not so simplistic now */
644c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
645c2c66affSColin Finck     startup.cb = sizeof(startup);
646c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
647c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
648c2c66affSColin Finck     startup.lpTitle = title;
649c2c66affSColin Finck     startup.lpDesktop = desktop;
650c2c66affSColin Finck     startup.dwXCountChars = 0x12121212;
651c2c66affSColin Finck     startup.dwYCountChars = 0x23232323;
652c2c66affSColin Finck     startup.dwX = 0x34343434;
653c2c66affSColin Finck     startup.dwY = 0x45454545;
654c2c66affSColin Finck     startup.dwXSize = 0x56565656;
655c2c66affSColin Finck     startup.dwYSize = 0x67676767;
656c2c66affSColin Finck     startup.dwFillAttribute = 0xA55A;
657c2c66affSColin Finck 
658c2c66affSColin Finck     get_file_name(resfile);
659c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
660c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
661c2c66affSColin Finck     /* wait for child to terminate */
662c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
663c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
664c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
6659ac94af4SThomas Faber     CloseHandle(info.hThread);
6669ac94af4SThomas Faber     CloseHandle(info.hProcess);
667c2c66affSColin Finck 
668c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
669c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
670c2c66affSColin Finck     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
671c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
672c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
673c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
674c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
675c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
676c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
677c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
678c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
679c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
680c2c66affSColin Finck     release_memory();
681c2c66affSColin Finck     DeleteFileA(resfile);
682c2c66affSColin Finck 
683c2c66affSColin Finck     /* not so simplistic now */
684c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
685c2c66affSColin Finck     startup.cb = sizeof(startup);
686c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
687c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
688c2c66affSColin Finck     startup.lpTitle = title;
689c2c66affSColin Finck     startup.lpDesktop = NULL;
690c2c66affSColin Finck     startup.dwXCountChars = 0x12121212;
691c2c66affSColin Finck     startup.dwYCountChars = 0x23232323;
692c2c66affSColin Finck     startup.dwX = 0x34343434;
693c2c66affSColin Finck     startup.dwY = 0x45454545;
694c2c66affSColin Finck     startup.dwXSize = 0x56565656;
695c2c66affSColin Finck     startup.dwYSize = 0x67676767;
696c2c66affSColin Finck     startup.dwFillAttribute = 0xA55A;
697c2c66affSColin Finck 
698c2c66affSColin Finck     get_file_name(resfile);
699c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
700c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
701c2c66affSColin Finck     /* wait for child to terminate */
702c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
703c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
704c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
7059ac94af4SThomas Faber     CloseHandle(info.hThread);
7069ac94af4SThomas Faber     CloseHandle(info.hProcess);
707c2c66affSColin Finck 
708c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
709c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
710c2c66affSColin Finck     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
711c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
712c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
713c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
714c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
715c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
716c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
717c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
718c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
719c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
720c2c66affSColin Finck     release_memory();
721c2c66affSColin Finck     DeleteFileA(resfile);
722c2c66affSColin Finck 
723c2c66affSColin Finck     /* not so simplistic now */
724c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
725c2c66affSColin Finck     startup.cb = sizeof(startup);
726c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
727c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
728c2c66affSColin Finck     startup.lpTitle = title;
729c2c66affSColin Finck     startup.lpDesktop = empty;
730c2c66affSColin Finck     startup.dwXCountChars = 0x12121212;
731c2c66affSColin Finck     startup.dwYCountChars = 0x23232323;
732c2c66affSColin Finck     startup.dwX = 0x34343434;
733c2c66affSColin Finck     startup.dwY = 0x45454545;
734c2c66affSColin Finck     startup.dwXSize = 0x56565656;
735c2c66affSColin Finck     startup.dwYSize = 0x67676767;
736c2c66affSColin Finck     startup.dwFillAttribute = 0xA55A;
737c2c66affSColin Finck 
738c2c66affSColin Finck     get_file_name(resfile);
739c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
740c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
741c2c66affSColin Finck     /* wait for child to terminate */
742c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
743c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
744c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
7459ac94af4SThomas Faber     CloseHandle(info.hThread);
7469ac94af4SThomas Faber     CloseHandle(info.hProcess);
747c2c66affSColin Finck 
748c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
749c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
750c2c66affSColin Finck     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
751c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
752c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
753c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
754c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
755c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
756c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
757c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
758c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
759c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
760c2c66affSColin Finck     release_memory();
761c2c66affSColin Finck     DeleteFileA(resfile);
762c2c66affSColin Finck 
763c2c66affSColin Finck     /* not so simplistic now */
764c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
765c2c66affSColin Finck     startup.cb = sizeof(startup);
766c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
767c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
768c2c66affSColin Finck     startup.lpTitle = NULL;
769c2c66affSColin Finck     startup.lpDesktop = desktop;
770c2c66affSColin Finck     startup.dwXCountChars = 0x12121212;
771c2c66affSColin Finck     startup.dwYCountChars = 0x23232323;
772c2c66affSColin Finck     startup.dwX = 0x34343434;
773c2c66affSColin Finck     startup.dwY = 0x45454545;
774c2c66affSColin Finck     startup.dwXSize = 0x56565656;
775c2c66affSColin Finck     startup.dwYSize = 0x67676767;
776c2c66affSColin Finck     startup.dwFillAttribute = 0xA55A;
777c2c66affSColin Finck 
778c2c66affSColin Finck     get_file_name(resfile);
779c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
780c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
781c2c66affSColin Finck     /* wait for child to terminate */
782c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
783c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
784c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
7859ac94af4SThomas Faber     CloseHandle(info.hThread);
7869ac94af4SThomas Faber     CloseHandle(info.hProcess);
787c2c66affSColin Finck 
788c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
789c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
790c2c66affSColin Finck     result = getChildString( "StartupInfoA", "lpTitle" );
791c2c66affSColin Finck     ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
792c2c66affSColin Finck         "expected '%s' or null, got '%s'\n", selfname, result );
793c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
794c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
795c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
796c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
797c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
798c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
799c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
800c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
801c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
802c2c66affSColin Finck     release_memory();
803c2c66affSColin Finck     DeleteFileA(resfile);
804c2c66affSColin Finck 
805c2c66affSColin Finck     /* not so simplistic now */
806c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
807c2c66affSColin Finck     startup.cb = sizeof(startup);
808c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
809c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
810c2c66affSColin Finck     startup.lpTitle = empty;
811c2c66affSColin Finck     startup.lpDesktop = desktop;
812c2c66affSColin Finck     startup.dwXCountChars = 0x12121212;
813c2c66affSColin Finck     startup.dwYCountChars = 0x23232323;
814c2c66affSColin Finck     startup.dwX = 0x34343434;
815c2c66affSColin Finck     startup.dwY = 0x45454545;
816c2c66affSColin Finck     startup.dwXSize = 0x56565656;
817c2c66affSColin Finck     startup.dwYSize = 0x67676767;
818c2c66affSColin Finck     startup.dwFillAttribute = 0xA55A;
819c2c66affSColin Finck 
820c2c66affSColin Finck     get_file_name(resfile);
821c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
822c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
823c2c66affSColin Finck     /* wait for child to terminate */
824c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
825c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
826c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
8279ac94af4SThomas Faber     CloseHandle(info.hThread);
8289ac94af4SThomas Faber     CloseHandle(info.hProcess);
829c2c66affSColin Finck 
830c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
831c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
832c2c66affSColin Finck     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
833c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
834c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
835c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
836c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
837c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
838c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
839c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
840c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
841c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
842c2c66affSColin Finck     release_memory();
843c2c66affSColin Finck     DeleteFileA(resfile);
844c2c66affSColin Finck 
845c2c66affSColin Finck     /* not so simplistic now */
846c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
847c2c66affSColin Finck     startup.cb = sizeof(startup);
848c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
849c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
850c2c66affSColin Finck     startup.lpTitle = empty;
851c2c66affSColin Finck     startup.lpDesktop = empty;
852c2c66affSColin Finck     startup.dwXCountChars = 0x12121212;
853c2c66affSColin Finck     startup.dwYCountChars = 0x23232323;
854c2c66affSColin Finck     startup.dwX = 0x34343434;
855c2c66affSColin Finck     startup.dwY = 0x45454545;
856c2c66affSColin Finck     startup.dwXSize = 0x56565656;
857c2c66affSColin Finck     startup.dwYSize = 0x67676767;
858c2c66affSColin Finck     startup.dwFillAttribute = 0xA55A;
859c2c66affSColin Finck 
860c2c66affSColin Finck     get_file_name(resfile);
861c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
862c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
863c2c66affSColin Finck     /* wait for child to terminate */
864c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
865c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
866c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
8679ac94af4SThomas Faber     CloseHandle(info.hThread);
8689ac94af4SThomas Faber     CloseHandle(info.hProcess);
869c2c66affSColin Finck 
870c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
871c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
872c2c66affSColin Finck     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
873c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
874c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
875c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
876c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
877c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
878c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
879c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
880c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
881c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
882c2c66affSColin Finck     release_memory();
883c2c66affSColin Finck     DeleteFileA(resfile);
884c2c66affSColin Finck 
885c2c66affSColin Finck     /* TODO: test for A/W and W/A and W/W */
886c2c66affSColin Finck }
887c2c66affSColin Finck 
test_CommandLine(void)888c2c66affSColin Finck static void test_CommandLine(void)
889c2c66affSColin Finck {
890c2c66affSColin Finck     char                buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
891c2c66affSColin Finck     char                buffer2[MAX_PATH];
892c2c66affSColin Finck     PROCESS_INFORMATION	info;
893c2c66affSColin Finck     STARTUPINFOA	startup;
894c2c66affSColin Finck     BOOL                ret;
895c2c66affSColin Finck 
896c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
897c2c66affSColin Finck     startup.cb = sizeof(startup);
898c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
899c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
900c2c66affSColin Finck 
901c2c66affSColin Finck     /* the basics */
902c2c66affSColin Finck     get_file_name(resfile);
903c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
904c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
905c2c66affSColin Finck     /* wait for child to terminate */
906c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
907c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
908c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
9099ac94af4SThomas Faber     CloseHandle(info.hThread);
9109ac94af4SThomas Faber     CloseHandle(info.hProcess);
911c2c66affSColin Finck 
912c2c66affSColin Finck     okChildInt("Arguments", "argcA", 5);
913c2c66affSColin Finck     okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
914c2c66affSColin Finck     okChildString("Arguments", "argvA5", NULL);
915c2c66affSColin Finck     okChildString("Arguments", "CommandLineA", buffer);
916c2c66affSColin Finck     release_memory();
917c2c66affSColin Finck     DeleteFileA(resfile);
918c2c66affSColin Finck 
919c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
920c2c66affSColin Finck     startup.cb = sizeof(startup);
921c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
922c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
923c2c66affSColin Finck 
924*8a437ac5STimo Kreuzer     /* from François */
925c2c66affSColin Finck     get_file_name(resfile);
926c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
927c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
928c2c66affSColin Finck     /* wait for child to terminate */
929c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
930c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
931c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
9329ac94af4SThomas Faber     CloseHandle(info.hThread);
9339ac94af4SThomas Faber     CloseHandle(info.hProcess);
934c2c66affSColin Finck 
935c2c66affSColin Finck     okChildInt("Arguments", "argcA", 7);
936c2c66affSColin Finck     okChildString("Arguments", "argvA4", "a\"b\\");
937c2c66affSColin Finck     okChildString("Arguments", "argvA5", "c\"");
938c2c66affSColin Finck     okChildString("Arguments", "argvA6", "d");
939c2c66affSColin Finck     okChildString("Arguments", "argvA7", NULL);
940c2c66affSColin Finck     okChildString("Arguments", "CommandLineA", buffer);
941c2c66affSColin Finck     release_memory();
942c2c66affSColin Finck     DeleteFileA(resfile);
943c2c66affSColin Finck 
944c2c66affSColin Finck     /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
945c2c66affSColin Finck     get_file_name(resfile);
946c2c66affSColin Finck     /* Use exename to avoid buffer containing things like 'C:' */
947c2c66affSColin Finck     sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
948c2c66affSColin Finck     SetLastError(0xdeadbeef);
949c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
950c2c66affSColin Finck     ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
951c2c66affSColin Finck     /* wait for child to terminate */
952c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
953c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
954c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
9559ac94af4SThomas Faber     CloseHandle(info.hThread);
9569ac94af4SThomas Faber     CloseHandle(info.hProcess);
957c2c66affSColin Finck     sprintf(buffer, "./%s", exename);
958c2c66affSColin Finck     okChildString("Arguments", "argvA0", buffer);
959c2c66affSColin Finck     release_memory();
960c2c66affSColin Finck     DeleteFileA(resfile);
961c2c66affSColin Finck 
962c2c66affSColin Finck     get_file_name(resfile);
963c2c66affSColin Finck     /* Use exename to avoid buffer containing things like 'C:' */
964c2c66affSColin Finck     sprintf(buffer, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
965c2c66affSColin Finck     SetLastError(0xdeadbeef);
966c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
967c2c66affSColin Finck     ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
968c2c66affSColin Finck     /* wait for child to terminate */
969c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
970c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
971c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
9729ac94af4SThomas Faber     CloseHandle(info.hThread);
9739ac94af4SThomas Faber     CloseHandle(info.hProcess);
974c2c66affSColin Finck     sprintf(buffer, ".\\%s", exename);
975c2c66affSColin Finck     okChildString("Arguments", "argvA0", buffer);
976c2c66affSColin Finck     release_memory();
977c2c66affSColin Finck     DeleteFileA(resfile);
978c2c66affSColin Finck 
979c2c66affSColin Finck     get_file_name(resfile);
980c2c66affSColin Finck     GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
981c2c66affSColin Finck     assert ( lpFilePart != 0);
982c2c66affSColin Finck     *(lpFilePart -1 ) = 0;
983c2c66affSColin Finck     p = strrchr(fullpath, '\\');
984c2c66affSColin Finck     /* Use exename to avoid buffer containing things like 'C:' */
985c2c66affSColin Finck     if (p) sprintf(buffer, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p, exename, resfile);
986c2c66affSColin Finck     else sprintf(buffer, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename, resfile);
987c2c66affSColin Finck     SetLastError(0xdeadbeef);
988c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
989c2c66affSColin Finck     ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
990c2c66affSColin Finck     /* wait for child to terminate */
991c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
992c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
993c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
9949ac94af4SThomas Faber     CloseHandle(info.hThread);
9959ac94af4SThomas Faber     CloseHandle(info.hProcess);
996c2c66affSColin Finck     if (p) sprintf(buffer, "..%s/%s", p, exename);
997c2c66affSColin Finck     else sprintf(buffer, "./%s", exename);
998c2c66affSColin Finck     okChildString("Arguments", "argvA0", buffer);
999c2c66affSColin Finck     release_memory();
1000c2c66affSColin Finck     DeleteFileA(resfile);
1001c2c66affSColin Finck 
1002c2c66affSColin Finck     /* Using AppName */
1003c2c66affSColin Finck     get_file_name(resfile);
1004c2c66affSColin Finck     GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
1005c2c66affSColin Finck     assert ( lpFilePart != 0);
1006c2c66affSColin Finck     *(lpFilePart -1 ) = 0;
1007c2c66affSColin Finck     p = strrchr(fullpath, '\\');
1008c2c66affSColin Finck     /* Use exename to avoid buffer containing things like 'C:' */
1009c2c66affSColin Finck     if (p) sprintf(buffer, "..%s/%s", p, exename);
1010c2c66affSColin Finck     else sprintf(buffer, "./%s", exename);
1011c2c66affSColin Finck     sprintf(buffer2, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile);
1012c2c66affSColin Finck     SetLastError(0xdeadbeef);
1013c2c66affSColin Finck     ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1014c2c66affSColin Finck     ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError());
1015c2c66affSColin Finck     /* wait for child to terminate */
1016c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1017c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
1018c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
10199ac94af4SThomas Faber     CloseHandle(info.hThread);
10209ac94af4SThomas Faber     CloseHandle(info.hProcess);
1021c2c66affSColin Finck     sprintf(buffer, "tests/process.c dump %s", resfile);
1022c2c66affSColin Finck     okChildString("Arguments", "argvA0", "dummy");
1023c2c66affSColin Finck     okChildString("Arguments", "CommandLineA", buffer2);
1024c2c66affSColin Finck     okChildStringWA("Arguments", "CommandLineW", buffer2);
1025c2c66affSColin Finck     release_memory();
1026c2c66affSColin Finck     DeleteFileA(resfile);
1027c2c66affSColin Finck 
1028c2c66affSColin Finck     if (0) /* Test crashes on NT-based Windows. */
1029c2c66affSColin Finck     {
1030c2c66affSColin Finck         /* Test NULL application name and command line parameters. */
1031c2c66affSColin Finck         SetLastError(0xdeadbeef);
1032c2c66affSColin Finck         ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1033c2c66affSColin Finck         ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1034c2c66affSColin Finck         ok(GetLastError() == ERROR_INVALID_PARAMETER,
1035c2c66affSColin Finck            "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1036c2c66affSColin Finck     }
1037c2c66affSColin Finck 
1038c2c66affSColin Finck     buffer[0] = '\0';
1039c2c66affSColin Finck 
1040c2c66affSColin Finck     /* Test empty application name parameter. */
1041c2c66affSColin Finck     SetLastError(0xdeadbeef);
1042c2c66affSColin Finck     ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1043c2c66affSColin Finck     ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1044c2c66affSColin Finck     ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1045c2c66affSColin Finck        broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1046c2c66affSColin Finck        broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1047c2c66affSColin Finck        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1048c2c66affSColin Finck 
1049c2c66affSColin Finck     buffer2[0] = '\0';
1050c2c66affSColin Finck 
1051c2c66affSColin Finck     /* Test empty application name and command line parameters. */
1052c2c66affSColin Finck     SetLastError(0xdeadbeef);
1053c2c66affSColin Finck     ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1054c2c66affSColin Finck     ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1055c2c66affSColin Finck     ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
1056c2c66affSColin Finck        broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
1057c2c66affSColin Finck        broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
1058c2c66affSColin Finck        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1059c2c66affSColin Finck 
1060c2c66affSColin Finck     /* Test empty command line parameter. */
1061c2c66affSColin Finck     SetLastError(0xdeadbeef);
1062c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1063c2c66affSColin Finck     ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1064c2c66affSColin Finck     ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
1065c2c66affSColin Finck        GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ ||
1066c2c66affSColin Finck        GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ ||
1067c2c66affSColin Finck        GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */,
1068c2c66affSColin Finck        "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1069c2c66affSColin Finck 
1070c2c66affSColin Finck     strcpy(buffer, "doesnotexist.exe");
1071c2c66affSColin Finck     strcpy(buffer2, "does not exist.exe");
1072c2c66affSColin Finck 
1073c2c66affSColin Finck     /* Test nonexistent application name. */
1074c2c66affSColin Finck     SetLastError(0xdeadbeef);
1075c2c66affSColin Finck     ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1076c2c66affSColin Finck     ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1077c2c66affSColin Finck     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1078c2c66affSColin Finck 
1079c2c66affSColin Finck     SetLastError(0xdeadbeef);
1080c2c66affSColin Finck     ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1081c2c66affSColin Finck     ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1082c2c66affSColin Finck     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1083c2c66affSColin Finck 
1084c2c66affSColin Finck     /* Test nonexistent command line parameter. */
1085c2c66affSColin Finck     SetLastError(0xdeadbeef);
1086c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1087c2c66affSColin Finck     ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1088c2c66affSColin Finck     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1089c2c66affSColin Finck 
1090c2c66affSColin Finck     SetLastError(0xdeadbeef);
1091c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
1092c2c66affSColin Finck     ok(!ret, "CreateProcessA unexpectedly succeeded\n");
1093c2c66affSColin Finck     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1094c2c66affSColin Finck }
1095c2c66affSColin Finck 
test_Directory(void)1096c2c66affSColin Finck static void test_Directory(void)
1097c2c66affSColin Finck {
1098c2c66affSColin Finck     char                buffer[MAX_PATH];
1099c2c66affSColin Finck     PROCESS_INFORMATION	info;
1100c2c66affSColin Finck     STARTUPINFOA	startup;
1101c2c66affSColin Finck     char windir[MAX_PATH];
1102c2c66affSColin Finck     static CHAR cmdline[] = "winver.exe";
1103c2c66affSColin Finck 
1104c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
1105c2c66affSColin Finck     startup.cb = sizeof(startup);
1106c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
1107c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
1108c2c66affSColin Finck 
1109c2c66affSColin Finck     /* the basics */
1110c2c66affSColin Finck     get_file_name(resfile);
1111c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1112c2c66affSColin Finck     GetWindowsDirectoryA( windir, sizeof(windir) );
1113c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n");
1114c2c66affSColin Finck     /* wait for child to terminate */
1115c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1116c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
1117c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
11189ac94af4SThomas Faber     CloseHandle(info.hThread);
11199ac94af4SThomas Faber     CloseHandle(info.hProcess);
1120c2c66affSColin Finck 
1121c2c66affSColin Finck     okChildIString("Misc", "CurrDirA", windir);
1122c2c66affSColin Finck     release_memory();
1123c2c66affSColin Finck     DeleteFileA(resfile);
1124c2c66affSColin Finck 
1125c2c66affSColin Finck     /* search PATH for the exe if directory is NULL */
1126c2c66affSColin Finck     ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1127c2c66affSColin Finck     ok(TerminateProcess(info.hProcess, 0), "Child process termination\n");
11289ac94af4SThomas Faber     CloseHandle(info.hThread);
11299ac94af4SThomas Faber     CloseHandle(info.hProcess);
1130c2c66affSColin Finck 
1131c2c66affSColin Finck     /* if any directory is provided, don't search PATH, error on bad directory */
1132c2c66affSColin Finck     SetLastError(0xdeadbeef);
1133c2c66affSColin Finck     memset(&info, 0, sizeof(info));
1134c2c66affSColin Finck     ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L,
1135c2c66affSColin Finck                        NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n");
1136c2c66affSColin Finck     ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1137c2c66affSColin Finck     ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n");
1138c2c66affSColin Finck }
1139c2c66affSColin Finck 
test_Toolhelp(void)1140c2c66affSColin Finck static void test_Toolhelp(void)
1141c2c66affSColin Finck {
1142c2c66affSColin Finck     char                buffer[MAX_PATH];
1143c2c66affSColin Finck     STARTUPINFOA        startup;
1144c2c66affSColin Finck     PROCESS_INFORMATION info;
1145c2c66affSColin Finck     HANDLE              process, thread, snapshot;
1146c2c66affSColin Finck     PROCESSENTRY32      pe;
1147c2c66affSColin Finck     THREADENTRY32       te;
1148c2c66affSColin Finck     DWORD               ret;
1149c2c66affSColin Finck     int                 i;
1150c2c66affSColin Finck 
1151*8a437ac5STimo Kreuzer #if defined(__REACTOS__) && defined(_M_AMD64)
1152*8a437ac5STimo Kreuzer     if (!winetest_interactive)
1153*8a437ac5STimo Kreuzer     {
1154*8a437ac5STimo Kreuzer         skip("ROSTESTS-372: Skipping test in kernel32_winetest:process test_Toolhelp because it leaves a process behind on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
1155*8a437ac5STimo Kreuzer         //return;
1156*8a437ac5STimo Kreuzer     }
1157*8a437ac5STimo Kreuzer #endif
1158*8a437ac5STimo Kreuzer 
1159c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
1160c2c66affSColin Finck     startup.cb = sizeof(startup);
1161c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
1162c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
1163c2c66affSColin Finck 
1164c2c66affSColin Finck     get_file_name(resfile);
1165c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1166c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1167c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1168c2c66affSColin Finck     CloseHandle(info.hProcess);
1169c2c66affSColin Finck     CloseHandle(info.hThread);
1170c2c66affSColin Finck 
1171c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1172c2c66affSColin Finck     okChildInt("Toolhelp", "cntUsage", 0);
1173c2c66affSColin Finck     okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1174c2c66affSColin Finck     okChildInt("Toolhelp", "th32ModuleID", 0);
1175c2c66affSColin Finck     okChildInt("Toolhelp", "th32ParentProcessID", GetCurrentProcessId());
1176c2c66affSColin Finck     /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1177c2c66affSColin Finck     okChildInt("Toolhelp", "dwFlags", 0);
1178c2c66affSColin Finck 
1179c2c66affSColin Finck     release_memory();
1180c2c66affSColin Finck     DeleteFileA(resfile);
1181c2c66affSColin Finck 
1182*8a437ac5STimo Kreuzer #if defined(__REACTOS__) && defined(_M_AMD64)
1183*8a437ac5STimo Kreuzer     if (!winetest_interactive)
1184*8a437ac5STimo Kreuzer     {
1185*8a437ac5STimo Kreuzer         skip("ROSTESTS-371: Skipping kernel32_winetest:sync test_apc_deadlock because it fails on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
1186*8a437ac5STimo Kreuzer     }
1187*8a437ac5STimo Kreuzer     else
1188*8a437ac5STimo Kreuzer     {
1189*8a437ac5STimo Kreuzer #endif
1190*8a437ac5STimo Kreuzer 
1191c2c66affSColin Finck     get_file_name(resfile);
1192c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c nested \"%s\"", selfname, resfile);
1193c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed\n");
1194c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1195c2c66affSColin Finck 
1196c2c66affSColin Finck     process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1197c2c66affSColin Finck     ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1198c2c66affSColin Finck     CloseHandle(process);
1199c2c66affSColin Finck 
1200c2c66affSColin Finck     CloseHandle(info.hProcess);
1201c2c66affSColin Finck     CloseHandle(info.hThread);
1202*8a437ac5STimo Kreuzer #if defined(__REACTOS__) && defined(_M_AMD64)
1203*8a437ac5STimo Kreuzer     }
1204*8a437ac5STimo Kreuzer #endif
1205c2c66affSColin Finck 
1206c2c66affSColin Finck     for (i = 0; i < 20; i++)
1207c2c66affSColin Finck     {
1208c2c66affSColin Finck         SetLastError(0xdeadbeef);
1209c2c66affSColin Finck         process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, info.dwProcessId);
1210c2c66affSColin Finck         ok(process || GetLastError() == ERROR_INVALID_PARAMETER, "OpenProcess failed %u\n", GetLastError());
1211c2c66affSColin Finck         if (!process) break;
1212c2c66affSColin Finck         CloseHandle(process);
1213c2c66affSColin Finck         Sleep(100);
1214c2c66affSColin Finck     }
1215c2c66affSColin Finck     /* The following test fails randomly on some Windows versions, but Gothic 2 depends on it */
1216c2c66affSColin Finck     ok(i < 20 || broken(i == 20), "process object not released\n");
1217c2c66affSColin Finck 
1218c2c66affSColin Finck     snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1219c2c66affSColin Finck     ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1220c2c66affSColin Finck     memset(&pe, 0, sizeof(pe));
1221c2c66affSColin Finck     pe.dwSize = sizeof(pe);
1222c2c66affSColin Finck     if (pProcess32First(snapshot, &pe))
1223c2c66affSColin Finck     {
1224c2c66affSColin Finck         while (pe.th32ParentProcessID != info.dwProcessId)
1225c2c66affSColin Finck             if (!pProcess32Next(snapshot, &pe)) break;
1226c2c66affSColin Finck     }
1227c2c66affSColin Finck     CloseHandle(snapshot);
1228c2c66affSColin Finck     ok(pe.th32ParentProcessID == info.dwProcessId, "failed to find nested child process\n");
1229c2c66affSColin Finck 
1230c2c66affSColin Finck     process = OpenProcess(PROCESS_ALL_ACCESS_NT4, FALSE, pe.th32ProcessID);
1231c2c66affSColin Finck     ok(process != NULL, "OpenProcess failed %u\n", GetLastError());
1232c2c66affSColin Finck 
1233c2c66affSColin Finck     snapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1234c2c66affSColin Finck     ok(snapshot != INVALID_HANDLE_VALUE, "CreateToolhelp32Snapshot failed %u\n", GetLastError());
1235c2c66affSColin Finck     memset(&te, 0, sizeof(te));
1236c2c66affSColin Finck     te.dwSize = sizeof(te);
1237c2c66affSColin Finck     if (pThread32First(snapshot, &te))
1238c2c66affSColin Finck     {
1239c2c66affSColin Finck         while (te.th32OwnerProcessID != pe.th32ProcessID)
1240c2c66affSColin Finck             if (!pThread32Next(snapshot, &te)) break;
1241c2c66affSColin Finck     }
1242c2c66affSColin Finck     CloseHandle(snapshot);
1243c2c66affSColin Finck     ok(te.th32OwnerProcessID == pe.th32ProcessID, "failed to find suspended thread\n");
1244c2c66affSColin Finck 
1245c2c66affSColin Finck     thread = OpenThread(THREAD_ALL_ACCESS_NT4, FALSE, te.th32ThreadID);
1246c2c66affSColin Finck     ok(thread != NULL, "OpenThread failed %u\n", GetLastError());
1247c2c66affSColin Finck     ret = ResumeThread(thread);
1248c2c66affSColin Finck     ok(ret == 1, "expected 1, got %u\n", ret);
1249c2c66affSColin Finck     CloseHandle(thread);
1250c2c66affSColin Finck 
1251c2c66affSColin Finck     ok(WaitForSingleObject(process, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1252c2c66affSColin Finck     CloseHandle(process);
1253c2c66affSColin Finck 
1254c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1255c2c66affSColin Finck     okChildInt("Toolhelp", "cntUsage", 0);
1256c2c66affSColin Finck     okChildInt("Toolhelp", "th32DefaultHeapID", 0);
1257c2c66affSColin Finck     okChildInt("Toolhelp", "th32ModuleID", 0);
1258c2c66affSColin Finck     okChildInt("Toolhelp", "th32ParentProcessID", info.dwProcessId);
1259c2c66affSColin Finck     /* pcPriClassBase differs between Windows versions (either 6 or 8) */
1260c2c66affSColin Finck     okChildInt("Toolhelp", "dwFlags", 0);
1261c2c66affSColin Finck 
1262c2c66affSColin Finck     release_memory();
1263c2c66affSColin Finck     DeleteFileA(resfile);
1264c2c66affSColin Finck }
1265c2c66affSColin Finck 
is_str_env_drive_dir(const char * str)1266c2c66affSColin Finck static BOOL is_str_env_drive_dir(const char* str)
1267c2c66affSColin Finck {
1268c2c66affSColin Finck     return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1269c2c66affSColin Finck         str[3] == '=' && str[4] == str[1];
1270c2c66affSColin Finck }
1271c2c66affSColin Finck 
1272c2c66affSColin Finck /* compared expected child's environment (in gesA) from actual
1273c2c66affSColin Finck  * environment our child got
1274c2c66affSColin Finck  */
cmpEnvironment(const char * gesA)1275c2c66affSColin Finck static void cmpEnvironment(const char* gesA)
1276c2c66affSColin Finck {
1277c2c66affSColin Finck     int                 i, clen;
1278c2c66affSColin Finck     const char*         ptrA;
1279c2c66affSColin Finck     char*               res;
1280c2c66affSColin Finck     char                key[32];
1281c2c66affSColin Finck     BOOL                found;
1282c2c66affSColin Finck 
1283c2c66affSColin Finck     clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1284c2c66affSColin Finck 
1285c2c66affSColin Finck     /* now look each parent env in child */
1286c2c66affSColin Finck     if ((ptrA = gesA) != NULL)
1287c2c66affSColin Finck     {
1288c2c66affSColin Finck         while (*ptrA)
1289c2c66affSColin Finck         {
1290c2c66affSColin Finck             for (i = 0; i < clen; i++)
1291c2c66affSColin Finck             {
1292c2c66affSColin Finck                 sprintf(key, "env%d", i);
1293c2c66affSColin Finck                 res = getChildString("EnvironmentA", key);
1294c2c66affSColin Finck                 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1295c2c66affSColin Finck                     break;
1296c2c66affSColin Finck             }
1297c2c66affSColin Finck             found = i < clen;
1298c2c66affSColin Finck             ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1299c2c66affSColin Finck 
1300c2c66affSColin Finck             ptrA += strlen(ptrA) + 1;
1301c2c66affSColin Finck             release_memory();
1302c2c66affSColin Finck         }
1303c2c66affSColin Finck     }
1304c2c66affSColin Finck     /* and each child env in parent */
1305c2c66affSColin Finck     for (i = 0; i < clen; i++)
1306c2c66affSColin Finck     {
1307c2c66affSColin Finck         sprintf(key, "env%d", i);
1308c2c66affSColin Finck         res = getChildString("EnvironmentA", key);
1309c2c66affSColin Finck         if ((ptrA = gesA) != NULL)
1310c2c66affSColin Finck         {
1311c2c66affSColin Finck             while (*ptrA)
1312c2c66affSColin Finck             {
1313c2c66affSColin Finck                 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1314c2c66affSColin Finck                     break;
1315c2c66affSColin Finck                 ptrA += strlen(ptrA) + 1;
1316c2c66affSColin Finck             }
1317c2c66affSColin Finck             if (!*ptrA) ptrA = NULL;
1318c2c66affSColin Finck         }
1319c2c66affSColin Finck 
1320c2c66affSColin Finck         if (!is_str_env_drive_dir(res))
1321c2c66affSColin Finck         {
1322c2c66affSColin Finck             found = ptrA != NULL;
1323c2c66affSColin Finck             ok(found, "Child-env string %s isn't in parent process\n", res);
1324c2c66affSColin Finck         }
1325c2c66affSColin Finck         /* else => should also test we get the right per drive default directory here... */
1326c2c66affSColin Finck     }
1327c2c66affSColin Finck }
1328c2c66affSColin Finck 
test_Environment(void)1329c2c66affSColin Finck static void test_Environment(void)
1330c2c66affSColin Finck {
1331c2c66affSColin Finck     char                buffer[MAX_PATH];
1332c2c66affSColin Finck     PROCESS_INFORMATION	info;
1333c2c66affSColin Finck     STARTUPINFOA	startup;
1334c2c66affSColin Finck     char                *child_env;
1335c2c66affSColin Finck     int                 child_env_len;
1336c2c66affSColin Finck     char                *ptr;
1337c2c66affSColin Finck     char                *ptr2;
1338c2c66affSColin Finck     char                *env;
1339c2c66affSColin Finck     int                 slen;
1340c2c66affSColin Finck 
1341c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
1342c2c66affSColin Finck     startup.cb = sizeof(startup);
1343c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
1344c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
1345c2c66affSColin Finck 
1346c2c66affSColin Finck     /* the basics */
1347c2c66affSColin Finck     get_file_name(resfile);
1348c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1349c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1350c2c66affSColin Finck     /* wait for child to terminate */
1351c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1352c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
1353c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1354c2c66affSColin Finck 
1355c2c66affSColin Finck     env = GetEnvironmentStringsA();
1356c2c66affSColin Finck     cmpEnvironment(env);
1357c2c66affSColin Finck     release_memory();
1358c2c66affSColin Finck     DeleteFileA(resfile);
1359c2c66affSColin Finck 
1360c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
1361c2c66affSColin Finck     startup.cb = sizeof(startup);
1362c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
1363c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
1364c2c66affSColin Finck 
1365c2c66affSColin Finck     /* the basics */
1366c2c66affSColin Finck     get_file_name(resfile);
1367c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1368c2c66affSColin Finck 
1369c2c66affSColin Finck     child_env_len = 0;
1370c2c66affSColin Finck     ptr = env;
1371c2c66affSColin Finck     while(*ptr)
1372c2c66affSColin Finck     {
1373c2c66affSColin Finck         slen = strlen(ptr)+1;
1374c2c66affSColin Finck         child_env_len += slen;
1375c2c66affSColin Finck         ptr += slen;
1376c2c66affSColin Finck     }
1377c2c66affSColin Finck     /* Add space for additional environment variables */
1378c2c66affSColin Finck     child_env_len += 256;
1379c2c66affSColin Finck     child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1380c2c66affSColin Finck 
1381c2c66affSColin Finck     ptr = child_env;
1382c2c66affSColin Finck     sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1383c2c66affSColin Finck     ptr += strlen(ptr) + 1;
1384c2c66affSColin Finck     strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1385c2c66affSColin Finck     ptr += strlen(ptr) + 1;
1386c2c66affSColin Finck     strcpy(ptr, "FOO=BAR");
1387c2c66affSColin Finck     ptr += strlen(ptr) + 1;
1388c2c66affSColin Finck     strcpy(ptr, "BAR=FOOBAR");
1389c2c66affSColin Finck     ptr += strlen(ptr) + 1;
1390c2c66affSColin Finck     /* copy all existing variables except:
1391c2c66affSColin Finck      * - WINELOADER
1392c2c66affSColin Finck      * - PATH (already set above)
1393c2c66affSColin Finck      * - the directory definitions (=[A-Z]:=)
1394c2c66affSColin Finck      */
1395c2c66affSColin Finck     for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1396c2c66affSColin Finck     {
1397c2c66affSColin Finck         if (strncmp(ptr2, "PATH=", 5) != 0 &&
1398c2c66affSColin Finck             strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1399c2c66affSColin Finck             !is_str_env_drive_dir(ptr2))
1400c2c66affSColin Finck         {
1401c2c66affSColin Finck             strcpy(ptr, ptr2);
1402c2c66affSColin Finck             ptr += strlen(ptr) + 1;
1403c2c66affSColin Finck         }
1404c2c66affSColin Finck     }
1405c2c66affSColin Finck     *ptr = '\0';
1406c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1407c2c66affSColin Finck     /* wait for child to terminate */
1408c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1409c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
1410c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1411c2c66affSColin Finck 
1412c2c66affSColin Finck     cmpEnvironment(child_env);
1413c2c66affSColin Finck 
1414c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, child_env);
1415c2c66affSColin Finck     FreeEnvironmentStringsA(env);
1416c2c66affSColin Finck     release_memory();
1417c2c66affSColin Finck     DeleteFileA(resfile);
1418c2c66affSColin Finck }
1419c2c66affSColin Finck 
test_SuspendFlag(void)1420c2c66affSColin Finck static  void    test_SuspendFlag(void)
1421c2c66affSColin Finck {
1422c2c66affSColin Finck     char                buffer[MAX_PATH];
1423c2c66affSColin Finck     PROCESS_INFORMATION	info;
1424c2c66affSColin Finck     STARTUPINFOA       startup, us;
1425c2c66affSColin Finck     DWORD               exit_status;
1426c2c66affSColin Finck     char *result;
1427c2c66affSColin Finck 
1428c2c66affSColin Finck     /* let's start simplistic */
1429c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
1430c2c66affSColin Finck     startup.cb = sizeof(startup);
1431c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
1432c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
1433c2c66affSColin Finck 
1434c2c66affSColin Finck     get_file_name(resfile);
1435c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1436c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1437c2c66affSColin Finck 
1438c2c66affSColin Finck     ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1439ed41a4deSAmine Khaldi     Sleep(1000);
1440c2c66affSColin Finck     ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1441c2c66affSColin Finck     ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1442c2c66affSColin Finck 
1443c2c66affSColin Finck     /* wait for child to terminate */
1444c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1445c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
1446c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1447c2c66affSColin Finck 
1448c2c66affSColin Finck     GetStartupInfoA(&us);
1449c2c66affSColin Finck 
1450c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
1451c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1452c2c66affSColin Finck     result = getChildString( "StartupInfoA", "lpTitle" );
1453c2c66affSColin Finck     ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1454c2c66affSColin Finck         "expected '%s' or null, got '%s'\n", selfname, result );
1455c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
1456c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
1457c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1458c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1459c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1460c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1461c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1462c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1463c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1464c2c66affSColin Finck     release_memory();
1465c2c66affSColin Finck     DeleteFileA(resfile);
1466c2c66affSColin Finck }
1467c2c66affSColin Finck 
test_DebuggingFlag(void)1468c2c66affSColin Finck static  void    test_DebuggingFlag(void)
1469c2c66affSColin Finck {
1470c2c66affSColin Finck     char                buffer[MAX_PATH];
1471c2c66affSColin Finck     void               *processbase = NULL;
1472c2c66affSColin Finck     PROCESS_INFORMATION	info;
1473c2c66affSColin Finck     STARTUPINFOA       startup, us;
1474c2c66affSColin Finck     DEBUG_EVENT         de;
1475c2c66affSColin Finck     unsigned            dbg = 0;
1476c2c66affSColin Finck     char *result;
1477c2c66affSColin Finck 
1478c2c66affSColin Finck     /* let's start simplistic */
1479c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
1480c2c66affSColin Finck     startup.cb = sizeof(startup);
1481c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
1482c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
1483c2c66affSColin Finck 
1484c2c66affSColin Finck     get_file_name(resfile);
1485c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
1486c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1487c2c66affSColin Finck 
1488c2c66affSColin Finck     /* get all startup events up to the entry point break exception */
1489c2c66affSColin Finck     do
1490c2c66affSColin Finck     {
1491c2c66affSColin Finck         ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1492c2c66affSColin Finck         ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1493c2c66affSColin Finck         if (!dbg)
1494c2c66affSColin Finck         {
1495c2c66affSColin Finck             ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1496c2c66affSColin Finck                "first event: %d\n", de.dwDebugEventCode);
1497c2c66affSColin Finck             processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1498c2c66affSColin Finck         }
1499c2c66affSColin Finck         if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1500c2c66affSColin Finck         ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT ||
1501c2c66affSColin Finck            de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1502c2c66affSColin Finck     } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1503c2c66affSColin Finck 
1504c2c66affSColin Finck     ok(dbg, "I have seen a debug event\n");
1505c2c66affSColin Finck     /* wait for child to terminate */
1506c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1507c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
1508c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1509c2c66affSColin Finck 
1510c2c66affSColin Finck     GetStartupInfoA(&us);
1511c2c66affSColin Finck 
1512c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
1513c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1514c2c66affSColin Finck     result = getChildString( "StartupInfoA", "lpTitle" );
1515c2c66affSColin Finck     ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1516c2c66affSColin Finck         "expected '%s' or null, got '%s'\n", selfname, result );
1517c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
1518c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
1519c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1520c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1521c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1522c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1523c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1524c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1525c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1526c2c66affSColin Finck     release_memory();
1527c2c66affSColin Finck     DeleteFileA(resfile);
1528c2c66affSColin Finck }
1529c2c66affSColin Finck 
is_console(HANDLE h)1530c2c66affSColin Finck static BOOL is_console(HANDLE h)
1531c2c66affSColin Finck {
1532c2c66affSColin Finck     return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1533c2c66affSColin Finck }
1534c2c66affSColin Finck 
test_Console(void)1535c2c66affSColin Finck static void test_Console(void)
1536c2c66affSColin Finck {
1537c2c66affSColin Finck     char                buffer[MAX_PATH];
1538c2c66affSColin Finck     PROCESS_INFORMATION	info;
1539c2c66affSColin Finck     STARTUPINFOA       startup, us;
1540c2c66affSColin Finck     SECURITY_ATTRIBUTES sa;
1541c2c66affSColin Finck     CONSOLE_SCREEN_BUFFER_INFO	sbi, sbiC;
1542c2c66affSColin Finck     DWORD               modeIn, modeOut, modeInC, modeOutC;
1543c2c66affSColin Finck     DWORD               cpIn, cpOut, cpInC, cpOutC;
1544c2c66affSColin Finck     DWORD               w;
1545c2c66affSColin Finck     HANDLE              hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1546c2c66affSColin Finck     const char*         msg = "This is a std-handle inheritance test.";
1547c2c66affSColin Finck     unsigned            msg_len;
1548c2c66affSColin Finck     BOOL                run_tests = TRUE;
1549c2c66affSColin Finck     char *result;
1550c2c66affSColin Finck 
1551c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
1552c2c66affSColin Finck     startup.cb = sizeof(startup);
1553c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1554c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
1555c2c66affSColin Finck 
1556c2c66affSColin Finck     sa.nLength = sizeof(sa);
1557c2c66affSColin Finck     sa.lpSecurityDescriptor = NULL;
1558c2c66affSColin Finck     sa.bInheritHandle = TRUE;
1559c2c66affSColin Finck 
1560c2c66affSColin Finck     startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1561c2c66affSColin Finck     startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1562c2c66affSColin Finck 
1563c2c66affSColin Finck     /* first, we need to be sure we're attached to a console */
1564c2c66affSColin Finck     if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1565c2c66affSColin Finck     {
1566c2c66affSColin Finck         /* we're not attached to a console, let's do it */
1567c2c66affSColin Finck         AllocConsole();
1568c2c66affSColin Finck         startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1569c2c66affSColin Finck         startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1570c2c66affSColin Finck     }
1571c2c66affSColin Finck     /* now verify everything's ok */
1572c2c66affSColin Finck     ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1573c2c66affSColin Finck     ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1574c2c66affSColin Finck     startup.hStdError = startup.hStdOutput;
1575c2c66affSColin Finck 
1576c2c66affSColin Finck     ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1577c2c66affSColin Finck     ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
1578c2c66affSColin Finck     ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
1579c2c66affSColin Finck     cpIn = GetConsoleCP();
1580c2c66affSColin Finck     cpOut = GetConsoleOutputCP();
1581c2c66affSColin Finck 
1582c2c66affSColin Finck     get_file_name(resfile);
1583c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" console", selfname, resfile);
1584c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1585c2c66affSColin Finck 
1586c2c66affSColin Finck     /* wait for child to terminate */
1587c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1588c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
1589c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1590c2c66affSColin Finck 
1591c2c66affSColin Finck     /* now get the modification the child has made, and resets parents expected values */
1592c2c66affSColin Finck     ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1593c2c66affSColin Finck     ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
1594c2c66affSColin Finck     ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
1595c2c66affSColin Finck 
1596c2c66affSColin Finck     SetConsoleMode(startup.hStdInput, modeIn);
1597c2c66affSColin Finck     SetConsoleMode(startup.hStdOutput, modeOut);
1598c2c66affSColin Finck 
1599c2c66affSColin Finck     cpInC = GetConsoleCP();
1600c2c66affSColin Finck     cpOutC = GetConsoleOutputCP();
1601c2c66affSColin Finck 
1602c2c66affSColin Finck     /* Try to set invalid CP */
1603c2c66affSColin Finck     SetLastError(0xdeadbeef);
1604c2c66affSColin Finck     ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1605c2c66affSColin Finck     ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1606c2c66affSColin Finck        broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1607c2c66affSColin Finck        "GetLastError: expecting %u got %u\n",
1608c2c66affSColin Finck        ERROR_INVALID_PARAMETER, GetLastError());
1609c2c66affSColin Finck     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1610c2c66affSColin Finck         run_tests = FALSE;
1611c2c66affSColin Finck 
1612c2c66affSColin Finck 
1613c2c66affSColin Finck     SetLastError(0xdeadbeef);
1614c2c66affSColin Finck     ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1615c2c66affSColin Finck     ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1616c2c66affSColin Finck        broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1617c2c66affSColin Finck        "GetLastError: expecting %u got %u\n",
1618c2c66affSColin Finck        ERROR_INVALID_PARAMETER, GetLastError());
1619c2c66affSColin Finck 
1620c2c66affSColin Finck     SetConsoleCP(cpIn);
1621c2c66affSColin Finck     SetConsoleOutputCP(cpOut);
1622c2c66affSColin Finck 
1623c2c66affSColin Finck     GetStartupInfoA(&us);
1624c2c66affSColin Finck 
1625c2c66affSColin Finck     okChildInt("StartupInfoA", "cb", startup.cb);
1626c2c66affSColin Finck     okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1627c2c66affSColin Finck     result = getChildString( "StartupInfoA", "lpTitle" );
1628c2c66affSColin Finck     ok( broken(!result) || (result && !strCmp( result, selfname, 0 )),
1629c2c66affSColin Finck         "expected '%s' or null, got '%s'\n", selfname, result );
1630c2c66affSColin Finck     okChildInt("StartupInfoA", "dwX", startup.dwX);
1631c2c66affSColin Finck     okChildInt("StartupInfoA", "dwY", startup.dwY);
1632c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1633c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1634c2c66affSColin Finck     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1635c2c66affSColin Finck     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1636c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1637c2c66affSColin Finck     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1638c2c66affSColin Finck     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1639c2c66affSColin Finck 
1640c2c66affSColin Finck     /* check child correctly inherited the console */
1641c2c66affSColin Finck     okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1642c2c66affSColin Finck     okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1643c2c66affSColin Finck     okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1644c2c66affSColin Finck     okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1645c2c66affSColin Finck     okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1646c2c66affSColin Finck     okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1647c2c66affSColin Finck     okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1648c2c66affSColin Finck     okChildInt("Console", "Attributes", sbi.wAttributes);
1649c2c66affSColin Finck     okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1650c2c66affSColin Finck     okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1651c2c66affSColin Finck     okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1652c2c66affSColin Finck     okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1653c2c66affSColin Finck     okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1654c2c66affSColin Finck     okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1655c2c66affSColin Finck     okChildInt("Console", "InputCP", cpIn);
1656c2c66affSColin Finck     okChildInt("Console", "OutputCP", cpOut);
1657c2c66affSColin Finck     okChildInt("Console", "InputMode", modeIn);
1658c2c66affSColin Finck     okChildInt("Console", "OutputMode", modeOut);
1659c2c66affSColin Finck 
1660c2c66affSColin Finck     if (run_tests)
1661c2c66affSColin Finck     {
1662c2c66affSColin Finck         ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1663c2c66affSColin Finck         ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1664c2c66affSColin Finck     }
1665c2c66affSColin Finck     else
1666c2c66affSColin Finck         win_skip("Setting the codepage is not implemented\n");
1667c2c66affSColin Finck 
1668c2c66affSColin Finck     ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1669c2c66affSColin Finck     ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1670c2c66affSColin Finck     trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1671c2c66affSColin Finck     ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1672c2c66affSColin Finck 
1673c2c66affSColin Finck     release_memory();
1674c2c66affSColin Finck     DeleteFileA(resfile);
1675c2c66affSColin Finck 
1676c2c66affSColin Finck     ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1677c2c66affSColin Finck     ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(),
1678c2c66affSColin Finck                        &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1679c2c66affSColin Finck        "Duplicating as inheritable child-output pipe\n");
1680c2c66affSColin Finck     CloseHandle(hChildOut);
1681c2c66affSColin Finck 
1682c2c66affSColin Finck     ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1683c2c66affSColin Finck     ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(),
1684c2c66affSColin Finck                        &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1685c2c66affSColin Finck        "Duplicating as inheritable child-input pipe\n");
1686c2c66affSColin Finck     CloseHandle(hChildIn);
1687c2c66affSColin Finck 
1688c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
1689c2c66affSColin Finck     startup.cb = sizeof(startup);
1690c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1691c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
1692c2c66affSColin Finck     startup.hStdInput = hChildInInh;
1693c2c66affSColin Finck     startup.hStdOutput = hChildOutInh;
1694c2c66affSColin Finck     startup.hStdError = hChildOutInh;
1695c2c66affSColin Finck 
1696c2c66affSColin Finck     get_file_name(resfile);
1697c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname, resfile);
1698c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1699c2c66affSColin Finck     ok(CloseHandle(hChildInInh), "Closing handle\n");
1700c2c66affSColin Finck     ok(CloseHandle(hChildOutInh), "Closing handle\n");
1701c2c66affSColin Finck 
1702c2c66affSColin Finck     msg_len = strlen(msg) + 1;
1703c2c66affSColin Finck     ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1704c2c66affSColin Finck     ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1705c2c66affSColin Finck     memset(buffer, 0, sizeof(buffer));
1706c2c66affSColin Finck     ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1707c2c66affSColin Finck     ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1708c2c66affSColin Finck 
1709ed41a4deSAmine Khaldi     /* the child may also send the final "n tests executed" string, so read it to avoid a deadlock */
1710ed41a4deSAmine Khaldi     ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL);
1711ed41a4deSAmine Khaldi 
1712c2c66affSColin Finck     /* wait for child to terminate */
1713c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1714c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
1715c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1716c2c66affSColin Finck 
1717c2c66affSColin Finck     okChildString("StdHandle", "msg", msg);
1718c2c66affSColin Finck 
1719c2c66affSColin Finck     release_memory();
1720c2c66affSColin Finck     DeleteFileA(resfile);
1721c2c66affSColin Finck }
1722c2c66affSColin Finck 
test_ExitCode(void)1723c2c66affSColin Finck static  void    test_ExitCode(void)
1724c2c66affSColin Finck {
1725c2c66affSColin Finck     char                buffer[MAX_PATH];
1726c2c66affSColin Finck     PROCESS_INFORMATION	info;
1727c2c66affSColin Finck     STARTUPINFOA	startup;
1728c2c66affSColin Finck     DWORD               code;
1729c2c66affSColin Finck 
1730c2c66affSColin Finck     /* let's start simplistic */
1731c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
1732c2c66affSColin Finck     startup.cb = sizeof(startup);
1733c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
1734c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
1735c2c66affSColin Finck 
1736c2c66affSColin Finck     get_file_name(resfile);
1737c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname, resfile);
1738c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1739c2c66affSColin Finck 
1740c2c66affSColin Finck     /* wait for child to terminate */
1741c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1742c2c66affSColin Finck     /* child process has changed result file, so let profile functions know about it */
1743c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1744c2c66affSColin Finck 
1745c2c66affSColin Finck     ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1746c2c66affSColin Finck     okChildInt("ExitCode", "value", code);
1747c2c66affSColin Finck 
1748c2c66affSColin Finck     release_memory();
1749c2c66affSColin Finck     DeleteFileA(resfile);
1750c2c66affSColin Finck }
1751c2c66affSColin Finck 
test_OpenProcess(void)1752c2c66affSColin Finck static void test_OpenProcess(void)
1753c2c66affSColin Finck {
1754c2c66affSColin Finck     HANDLE hproc;
1755c2c66affSColin Finck     void *addr1;
1756c2c66affSColin Finck     MEMORY_BASIC_INFORMATION info;
1757c2c66affSColin Finck     SIZE_T dummy, read_bytes;
1758c2c66affSColin Finck     BOOL ret;
1759c2c66affSColin Finck 
1760c2c66affSColin Finck     /* not exported in all windows versions */
1761c2c66affSColin Finck     if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1762c2c66affSColin Finck         win_skip("VirtualAllocEx not found\n");
1763c2c66affSColin Finck         return;
1764c2c66affSColin Finck     }
1765c2c66affSColin Finck 
1766c2c66affSColin Finck     /* without PROCESS_VM_OPERATION */
1767c2c66affSColin Finck     hproc = OpenProcess(PROCESS_ALL_ACCESS_NT4 & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1768c2c66affSColin Finck     ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1769c2c66affSColin Finck 
1770c2c66affSColin Finck     SetLastError(0xdeadbeef);
1771c2c66affSColin Finck     addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1772c2c66affSColin Finck     ok(!addr1, "VirtualAllocEx should fail\n");
1773c2c66affSColin Finck     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1774c2c66affSColin Finck     {   /* Win9x */
1775c2c66affSColin Finck         CloseHandle(hproc);
1776c2c66affSColin Finck         win_skip("VirtualAllocEx not implemented\n");
1777c2c66affSColin Finck         return;
1778c2c66affSColin Finck     }
1779c2c66affSColin Finck     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1780c2c66affSColin Finck 
1781c2c66affSColin Finck     read_bytes = 0xdeadbeef;
1782c2c66affSColin Finck     SetLastError(0xdeadbeef);
1783c2c66affSColin Finck     ret = ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes);
1784c2c66affSColin Finck     ok(ret, "ReadProcessMemory error %d\n", GetLastError());
1785c2c66affSColin Finck     ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1786c2c66affSColin Finck 
1787c2c66affSColin Finck     CloseHandle(hproc);
1788c2c66affSColin Finck 
1789c2c66affSColin Finck     hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1790c2c66affSColin Finck     ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1791c2c66affSColin Finck 
1792c2c66affSColin Finck     addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1793c2c66affSColin Finck     ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1794c2c66affSColin Finck 
1795c2c66affSColin Finck     /* without PROCESS_QUERY_INFORMATION */
1796c2c66affSColin Finck     SetLastError(0xdeadbeef);
1797c2c66affSColin Finck     ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1798c2c66affSColin Finck        "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1799c2c66affSColin Finck     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1800c2c66affSColin Finck 
1801c2c66affSColin Finck     /* without PROCESS_VM_READ */
1802c2c66affSColin Finck     read_bytes = 0xdeadbeef;
1803c2c66affSColin Finck     SetLastError(0xdeadbeef);
1804c2c66affSColin Finck     ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1805c2c66affSColin Finck        "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1806c2c66affSColin Finck     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1807c2c66affSColin Finck     ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1808c2c66affSColin Finck 
1809c2c66affSColin Finck     CloseHandle(hproc);
1810c2c66affSColin Finck 
1811c2c66affSColin Finck     hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1812c2c66affSColin Finck 
1813c2c66affSColin Finck     memset(&info, 0xcc, sizeof(info));
1814c2c66affSColin Finck     read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1815c2c66affSColin Finck     ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1816c2c66affSColin Finck 
1817c2c66affSColin Finck     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1818c2c66affSColin Finck     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1819c2c66affSColin Finck     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1820c2c66affSColin Finck     ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1821c2c66affSColin Finck     ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1822c2c66affSColin Finck     /* NT reports Protect == 0 for a not committed memory block */
1823c2c66affSColin Finck     ok(info.Protect == 0 /* NT */ ||
1824c2c66affSColin Finck        info.Protect == PAGE_NOACCESS, /* Win9x */
1825c2c66affSColin Finck         "%x != PAGE_NOACCESS\n", info.Protect);
1826c2c66affSColin Finck     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1827c2c66affSColin Finck 
1828c2c66affSColin Finck     SetLastError(0xdeadbeef);
1829c2c66affSColin Finck     ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1830c2c66affSColin Finck        "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1831c2c66affSColin Finck     ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1832c2c66affSColin Finck 
1833c2c66affSColin Finck     CloseHandle(hproc);
1834c2c66affSColin Finck 
1835c2c66affSColin Finck     hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
1836c2c66affSColin Finck     if (hproc)
1837c2c66affSColin Finck     {
1838c2c66affSColin Finck         SetLastError(0xdeadbeef);
1839c2c66affSColin Finck         memset(&info, 0xcc, sizeof(info));
1840c2c66affSColin Finck         read_bytes = VirtualQueryEx(hproc, addr1, &info, sizeof(info));
1841c2c66affSColin Finck         if (read_bytes) /* win8 */
1842c2c66affSColin Finck         {
1843c2c66affSColin Finck             ok(read_bytes == sizeof(info), "VirtualQueryEx error %d\n", GetLastError());
1844c2c66affSColin Finck             ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1845c2c66affSColin Finck             ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1846c2c66affSColin Finck             ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1847c2c66affSColin Finck             ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1848c2c66affSColin Finck             ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1849c2c66affSColin Finck             ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
1850c2c66affSColin Finck             ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1851c2c66affSColin Finck         }
1852c2c66affSColin Finck         else /* before win8 */
1853c2c66affSColin Finck             ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1854c2c66affSColin Finck 
1855c2c66affSColin Finck         SetLastError(0xdeadbeef);
1856c2c66affSColin Finck         ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1857c2c66affSColin Finck            "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1858c2c66affSColin Finck         ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1859c2c66affSColin Finck 
1860c2c66affSColin Finck         CloseHandle(hproc);
1861c2c66affSColin Finck     }
1862c2c66affSColin Finck 
1863c2c66affSColin Finck     ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1864c2c66affSColin Finck }
1865c2c66affSColin Finck 
test_GetProcessVersion(void)1866c2c66affSColin Finck static void test_GetProcessVersion(void)
1867c2c66affSColin Finck {
1868c2c66affSColin Finck     static char cmdline[] = "winver.exe";
1869c2c66affSColin Finck     PROCESS_INFORMATION pi;
1870c2c66affSColin Finck     STARTUPINFOA si;
1871c2c66affSColin Finck     DWORD ret;
1872c2c66affSColin Finck 
1873c2c66affSColin Finck     SetLastError(0xdeadbeef);
1874c2c66affSColin Finck     ret = GetProcessVersion(0);
1875c2c66affSColin Finck     ok(ret, "GetProcessVersion error %u\n", GetLastError());
1876c2c66affSColin Finck 
1877c2c66affSColin Finck     SetLastError(0xdeadbeef);
1878c2c66affSColin Finck     ret = GetProcessVersion(GetCurrentProcessId());
1879c2c66affSColin Finck     ok(ret, "GetProcessVersion error %u\n", GetLastError());
1880c2c66affSColin Finck 
1881c2c66affSColin Finck     memset(&si, 0, sizeof(si));
1882c2c66affSColin Finck     si.cb = sizeof(si);
1883c2c66affSColin Finck     si.dwFlags = STARTF_USESHOWWINDOW;
1884c2c66affSColin Finck     si.wShowWindow = SW_HIDE;
1885c2c66affSColin Finck     SetLastError(0xdeadbeef);
1886c2c66affSColin Finck     ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1887c2c66affSColin Finck     ok(ret, "CreateProcess error %u\n", GetLastError());
1888c2c66affSColin Finck 
1889c2c66affSColin Finck     SetLastError(0xdeadbeef);
1890c2c66affSColin Finck     ret = GetProcessVersion(pi.dwProcessId);
1891c2c66affSColin Finck     ok(ret, "GetProcessVersion error %u\n", GetLastError());
1892c2c66affSColin Finck 
1893c2c66affSColin Finck     SetLastError(0xdeadbeef);
1894c2c66affSColin Finck     ret = TerminateProcess(pi.hProcess, 0);
1895c2c66affSColin Finck     ok(ret, "TerminateProcess error %u\n", GetLastError());
1896c2c66affSColin Finck 
1897c2c66affSColin Finck     CloseHandle(pi.hProcess);
1898c2c66affSColin Finck     CloseHandle(pi.hThread);
1899c2c66affSColin Finck }
1900c2c66affSColin Finck 
test_GetProcessImageFileNameA(void)1901c2c66affSColin Finck static void test_GetProcessImageFileNameA(void)
1902c2c66affSColin Finck {
1903c2c66affSColin Finck     DWORD rc;
1904c2c66affSColin Finck     CHAR process[MAX_PATH];
1905c2c66affSColin Finck     static const char harddisk[] = "\\Device\\HarddiskVolume";
1906c2c66affSColin Finck 
1907c2c66affSColin Finck     if (!pK32GetProcessImageFileNameA)
1908c2c66affSColin Finck     {
1909c2c66affSColin Finck         win_skip("K32GetProcessImageFileNameA is unavailable\n");
1910c2c66affSColin Finck         return;
1911c2c66affSColin Finck     }
1912c2c66affSColin Finck 
1913c2c66affSColin Finck     /* callers must guess the buffer size */
1914c2c66affSColin Finck     SetLastError(0xdeadbeef);
1915c2c66affSColin Finck     rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL, 0);
1916c2c66affSColin Finck     ok(!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1917c2c66affSColin Finck        "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc, GetLastError());
1918c2c66affSColin Finck 
1919c2c66affSColin Finck     *process = '\0';
1920c2c66affSColin Finck     rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1921c2c66affSColin Finck     expect_eq_d(rc, lstrlenA(process));
1922c2c66affSColin Finck     if (strncmp(process, harddisk, lstrlenA(harddisk)))
1923c2c66affSColin Finck     {
1924c2c66affSColin Finck         todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1925c2c66affSColin Finck         return;
1926c2c66affSColin Finck     }
1927c2c66affSColin Finck 
1928c2c66affSColin Finck     if (!pQueryFullProcessImageNameA)
1929c2c66affSColin Finck         win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1930c2c66affSColin Finck     else
1931c2c66affSColin Finck     {
1932c2c66affSColin Finck         CHAR image[MAX_PATH];
1933c2c66affSColin Finck         DWORD length;
1934c2c66affSColin Finck 
1935c2c66affSColin Finck         length = sizeof(image);
1936c2c66affSColin Finck         expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE, image, &length));
1937c2c66affSColin Finck         expect_eq_d(length, lstrlenA(image));
1938c2c66affSColin Finck         ok(lstrcmpiA(process, image) == 0, "expected '%s' to be equal to '%s'\n", process, image);
1939c2c66affSColin Finck     }
1940c2c66affSColin Finck }
1941c2c66affSColin Finck 
test_QueryFullProcessImageNameA(void)1942c2c66affSColin Finck static void test_QueryFullProcessImageNameA(void)
1943c2c66affSColin Finck {
1944c2c66affSColin Finck #define INIT_STR "Just some words"
1945c2c66affSColin Finck     DWORD length, size;
1946c2c66affSColin Finck     CHAR buf[MAX_PATH], module[MAX_PATH];
1947c2c66affSColin Finck 
1948c2c66affSColin Finck     if (!pQueryFullProcessImageNameA)
1949c2c66affSColin Finck     {
1950c2c66affSColin Finck         win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1951c2c66affSColin Finck         return;
1952c2c66affSColin Finck     }
1953c2c66affSColin Finck 
1954c2c66affSColin Finck     *module = '\0';
1955c2c66affSColin Finck     SetLastError(0); /* old Windows don't reset it on success */
1956c2c66affSColin Finck     size = GetModuleFileNameA(NULL, module, sizeof(module));
1957c2c66affSColin Finck     ok(size && GetLastError() != ERROR_INSUFFICIENT_BUFFER, "GetModuleFileName failed: %u le=%u\n", size, GetLastError());
1958c2c66affSColin Finck 
1959c2c66affSColin Finck     /* get the buffer length without \0 terminator */
1960c2c66affSColin Finck     length = sizeof(buf);
1961c2c66affSColin Finck     expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1962c2c66affSColin Finck     expect_eq_d(length, lstrlenA(buf));
1963c2c66affSColin Finck     ok((buf[0] == '\\' && buf[1] == '\\') ||
1964c2c66affSColin Finck        lstrcmpiA(buf, module) == 0, "expected %s to match %s\n", buf, module);
1965c2c66affSColin Finck 
1966c2c66affSColin Finck     /*  when the buffer is too small
1967c2c66affSColin Finck      *  - function fail with error ERROR_INSUFFICIENT_BUFFER
1968c2c66affSColin Finck      *  - the size variable is not modified
1969c2c66affSColin Finck      * tested with the biggest too small size
1970c2c66affSColin Finck      */
1971c2c66affSColin Finck     size = length;
1972c2c66affSColin Finck     sprintf(buf,INIT_STR);
1973c2c66affSColin Finck     expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1974c2c66affSColin Finck     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1975c2c66affSColin Finck     expect_eq_d(length, size);
1976c2c66affSColin Finck     expect_eq_s(INIT_STR, buf);
1977c2c66affSColin Finck 
1978c2c66affSColin Finck     /* retest with smaller buffer size
1979c2c66affSColin Finck      */
1980c2c66affSColin Finck     size = 4;
1981c2c66affSColin Finck     sprintf(buf,INIT_STR);
1982c2c66affSColin Finck     expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1983c2c66affSColin Finck     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1984c2c66affSColin Finck     expect_eq_d(4, size);
1985c2c66affSColin Finck     expect_eq_s(INIT_STR, buf);
1986c2c66affSColin Finck 
1987c2c66affSColin Finck     /* this is a difference between the ascii and the unicode version
1988c2c66affSColin Finck      * the unicode version crashes when the size is big enough to hold
1989c2c66affSColin Finck      * the result while the ascii version throws an error
1990c2c66affSColin Finck      */
1991c2c66affSColin Finck     size = 1024;
1992c2c66affSColin Finck     expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1993c2c66affSColin Finck     expect_eq_d(1024, size);
1994c2c66affSColin Finck     expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
1995c2c66affSColin Finck }
1996c2c66affSColin Finck 
test_QueryFullProcessImageNameW(void)1997c2c66affSColin Finck static void test_QueryFullProcessImageNameW(void)
1998c2c66affSColin Finck {
1999c2c66affSColin Finck     HANDLE hSelf;
2000c2c66affSColin Finck     WCHAR module_name[1024], device[1024];
2001c2c66affSColin Finck     WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
2002c2c66affSColin Finck     WCHAR buf[1024];
2003c2c66affSColin Finck     DWORD size, len;
2004c2c66affSColin Finck 
2005c2c66affSColin Finck     if (!pQueryFullProcessImageNameW)
2006c2c66affSColin Finck     {
2007c2c66affSColin Finck         win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
2008c2c66affSColin Finck         return;
2009c2c66affSColin Finck     }
2010c2c66affSColin Finck 
2011c2c66affSColin Finck     ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
2012c2c66affSColin Finck 
2013c2c66affSColin Finck     /* GetCurrentProcess pseudo-handle */
2014c2c66affSColin Finck     size = sizeof(buf) / sizeof(buf[0]);
2015c2c66affSColin Finck     expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
2016c2c66affSColin Finck     expect_eq_d(lstrlenW(buf), size);
2017c2c66affSColin Finck     expect_eq_ws_i(buf, module_name);
2018c2c66affSColin Finck 
2019c2c66affSColin Finck     hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
2020c2c66affSColin Finck     /* Real handle */
2021c2c66affSColin Finck     size = sizeof(buf) / sizeof(buf[0]);
2022c2c66affSColin Finck     expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2023c2c66affSColin Finck     expect_eq_d(lstrlenW(buf), size);
2024c2c66affSColin Finck     expect_eq_ws_i(buf, module_name);
2025c2c66affSColin Finck 
2026c2c66affSColin Finck     /* Buffer too small */
2027c2c66affSColin Finck     size = lstrlenW(module_name)/2;
2028c2c66affSColin Finck     lstrcpyW(buf, deviceW);
2029c2c66affSColin Finck     SetLastError(0xdeadbeef);
2030c2c66affSColin Finck     expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2031c2c66affSColin Finck     expect_eq_d(lstrlenW(module_name)/2, size);  /* size not changed(!) */
2032c2c66affSColin Finck     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2033c2c66affSColin Finck     expect_eq_ws_i(deviceW, buf);  /* buffer not changed */
2034c2c66affSColin Finck 
2035c2c66affSColin Finck     /* Too small - not space for NUL terminator */
2036c2c66affSColin Finck     size = lstrlenW(module_name);
2037c2c66affSColin Finck     SetLastError(0xdeadbeef);
2038c2c66affSColin Finck     expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2039c2c66affSColin Finck     expect_eq_d(lstrlenW(module_name), size);  /* size not changed(!) */
2040c2c66affSColin Finck     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2041c2c66affSColin Finck 
2042c2c66affSColin Finck     /* NULL buffer */
2043c2c66affSColin Finck     size = 0;
2044c2c66affSColin Finck     expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
2045c2c66affSColin Finck     expect_eq_d(0, size);
2046c2c66affSColin Finck     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2047c2c66affSColin Finck 
2048c2c66affSColin Finck     /* Buffer too small */
2049c2c66affSColin Finck     size = lstrlenW(module_name)/2;
2050c2c66affSColin Finck     SetLastError(0xdeadbeef);
2051c2c66affSColin Finck     lstrcpyW(buf, module_name);
2052c2c66affSColin Finck     expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
2053c2c66affSColin Finck     expect_eq_d(lstrlenW(module_name)/2, size);  /* size not changed(!) */
2054c2c66affSColin Finck     expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
2055c2c66affSColin Finck     expect_eq_ws_i(module_name, buf);  /* buffer not changed */
2056c2c66affSColin Finck 
2057c2c66affSColin Finck 
2058c2c66affSColin Finck     /* native path */
2059c2c66affSColin Finck     size = sizeof(buf) / sizeof(buf[0]);
2060c2c66affSColin Finck     expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
2061c2c66affSColin Finck     expect_eq_d(lstrlenW(buf), size);
2062c2c66affSColin Finck     ok(buf[0] == '\\', "NT path should begin with '\\'\n");
2063c2c66affSColin Finck     ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
2064c2c66affSColin Finck 
2065c2c66affSColin Finck     module_name[2] = '\0';
2066c2c66affSColin Finck     *device = '\0';
2067c2c66affSColin Finck     size = QueryDosDeviceW(module_name, device, sizeof(device)/sizeof(device[0]));
2068c2c66affSColin Finck     ok(size, "QueryDosDeviceW failed: le=%u\n", GetLastError());
2069c2c66affSColin Finck     len = lstrlenW(device);
2070c2c66affSColin Finck     ok(size >= len+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size, len, wine_dbgstr_w(device));
2071c2c66affSColin Finck 
2072c2c66affSColin Finck     if (size >= lstrlenW(buf))
2073c2c66affSColin Finck     {
2074c2c66affSColin Finck         ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2075c2c66affSColin Finck     }
2076c2c66affSColin Finck     else
2077c2c66affSColin Finck     {
2078c2c66affSColin Finck         ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
2079c2c66affSColin Finck         buf[len] = '\0';
2080c2c66affSColin Finck         ok(lstrcmpiW(device, buf) == 0, "expected %s to match %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
2081c2c66affSColin Finck         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));
2082c2c66affSColin Finck     }
2083c2c66affSColin Finck 
2084c2c66affSColin Finck     CloseHandle(hSelf);
2085c2c66affSColin Finck }
2086c2c66affSColin Finck 
test_Handles(void)2087c2c66affSColin Finck static void test_Handles(void)
2088c2c66affSColin Finck {
2089c2c66affSColin Finck     HANDLE handle = GetCurrentProcess();
2090c2c66affSColin Finck     HANDLE h2, h3;
2091c2c66affSColin Finck     BOOL ret;
2092c2c66affSColin Finck     DWORD code;
2093c2c66affSColin Finck 
2094c2c66affSColin Finck     ok( handle == (HANDLE)~(ULONG_PTR)0 ||
2095c2c66affSColin Finck         handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
2096c2c66affSColin Finck         "invalid current process handle %p\n", handle );
2097c2c66affSColin Finck     ret = GetExitCodeProcess( handle, &code );
2098c2c66affSColin Finck     ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2099c2c66affSColin Finck #ifdef _WIN64
2100c2c66affSColin Finck     /* truncated handle */
2101c2c66affSColin Finck     SetLastError( 0xdeadbeef );
2102c2c66affSColin Finck     handle = (HANDLE)((ULONG_PTR)handle & ~0u);
2103c2c66affSColin Finck     ret = GetExitCodeProcess( handle, &code );
2104c2c66affSColin Finck     ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2105c2c66affSColin Finck     ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2106c2c66affSColin Finck     /* sign-extended handle */
2107c2c66affSColin Finck     SetLastError( 0xdeadbeef );
2108c2c66affSColin Finck     handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle);
2109c2c66affSColin Finck     ret = GetExitCodeProcess( handle, &code );
2110c2c66affSColin Finck     ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
2111c2c66affSColin Finck     /* invalid high-word */
2112c2c66affSColin Finck     SetLastError( 0xdeadbeef );
2113c2c66affSColin Finck     handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
2114c2c66affSColin Finck     ret = GetExitCodeProcess( handle, &code );
2115c2c66affSColin Finck     ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
2116c2c66affSColin Finck     ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
2117c2c66affSColin Finck #endif
2118c2c66affSColin Finck 
2119c2c66affSColin Finck     handle = GetStdHandle( STD_ERROR_HANDLE );
2120c2c66affSColin Finck     ok( handle != 0, "handle %p\n", handle );
2121c2c66affSColin Finck     DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &h3,
2122c2c66affSColin Finck                      0, TRUE, DUPLICATE_SAME_ACCESS );
2123c2c66affSColin Finck     SetStdHandle( STD_ERROR_HANDLE, h3 );
2124c2c66affSColin Finck     CloseHandle( (HANDLE)STD_ERROR_HANDLE );
2125c2c66affSColin Finck     h2 = GetStdHandle( STD_ERROR_HANDLE );
2126c2c66affSColin Finck     ok( h2 == 0 ||
2127c2c66affSColin Finck         broken( h2 == h3) || /* nt4, w2k */
2128c2c66affSColin Finck         broken( h2 == INVALID_HANDLE_VALUE),  /* win9x */
2129c2c66affSColin Finck         "wrong handle %p/%p\n", h2, h3 );
2130c2c66affSColin Finck     SetStdHandle( STD_ERROR_HANDLE, handle );
2131c2c66affSColin Finck }
2132c2c66affSColin Finck 
test_IsWow64Process(void)2133c2c66affSColin Finck static void test_IsWow64Process(void)
2134c2c66affSColin Finck {
2135c2c66affSColin Finck     PROCESS_INFORMATION pi;
2136c2c66affSColin Finck     STARTUPINFOA si;
2137c2c66affSColin Finck     DWORD ret;
2138c2c66affSColin Finck     BOOL is_wow64;
2139c2c66affSColin Finck     static char cmdline[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
2140c2c66affSColin Finck     static char cmdline_wow64[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
2141c2c66affSColin Finck 
2142c2c66affSColin Finck     if (!pIsWow64Process)
2143c2c66affSColin Finck     {
2144c2c66affSColin Finck         skip("IsWow64Process is not available\n");
2145c2c66affSColin Finck         return;
2146c2c66affSColin Finck     }
2147c2c66affSColin Finck 
2148c2c66affSColin Finck     memset(&si, 0, sizeof(si));
2149c2c66affSColin Finck     si.cb = sizeof(si);
2150c2c66affSColin Finck     si.dwFlags = STARTF_USESHOWWINDOW;
2151c2c66affSColin Finck     si.wShowWindow = SW_HIDE;
2152c2c66affSColin Finck     ret = CreateProcessA(NULL, cmdline_wow64, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2153c2c66affSColin Finck     if (ret)
2154c2c66affSColin Finck     {
2155c2c66affSColin Finck         trace("Created process %s\n", cmdline_wow64);
2156c2c66affSColin Finck         is_wow64 = FALSE;
2157c2c66affSColin Finck         ret = pIsWow64Process(pi.hProcess, &is_wow64);
2158c2c66affSColin Finck         ok(ret, "IsWow64Process failed.\n");
2159c2c66affSColin Finck         ok(is_wow64, "is_wow64 returned FALSE.\n");
2160c2c66affSColin Finck 
2161c2c66affSColin Finck         ret = TerminateProcess(pi.hProcess, 0);
2162c2c66affSColin Finck         ok(ret, "TerminateProcess error\n");
2163c2c66affSColin Finck 
2164c2c66affSColin Finck         CloseHandle(pi.hProcess);
2165c2c66affSColin Finck         CloseHandle(pi.hThread);
2166c2c66affSColin Finck     }
2167c2c66affSColin Finck 
2168c2c66affSColin Finck     memset(&si, 0, sizeof(si));
2169c2c66affSColin Finck     si.cb = sizeof(si);
2170c2c66affSColin Finck     si.dwFlags = STARTF_USESHOWWINDOW;
2171c2c66affSColin Finck     si.wShowWindow = SW_HIDE;
2172c2c66affSColin Finck     ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2173c2c66affSColin Finck     if (ret)
2174c2c66affSColin Finck     {
2175c2c66affSColin Finck         trace("Created process %s\n", cmdline);
2176c2c66affSColin Finck         is_wow64 = TRUE;
2177c2c66affSColin Finck         ret = pIsWow64Process(pi.hProcess, &is_wow64);
2178c2c66affSColin Finck         ok(ret, "IsWow64Process failed.\n");
2179c2c66affSColin Finck         ok(!is_wow64, "is_wow64 returned TRUE.\n");
2180c2c66affSColin Finck 
2181c2c66affSColin Finck         ret = TerminateProcess(pi.hProcess, 0);
2182c2c66affSColin Finck         ok(ret, "TerminateProcess error\n");
2183c2c66affSColin Finck 
2184c2c66affSColin Finck         CloseHandle(pi.hProcess);
2185c2c66affSColin Finck         CloseHandle(pi.hThread);
2186c2c66affSColin Finck     }
2187c2c66affSColin Finck }
2188c2c66affSColin Finck 
test_SystemInfo(void)2189c2c66affSColin Finck static void test_SystemInfo(void)
2190c2c66affSColin Finck {
2191c2c66affSColin Finck     SYSTEM_INFO si, nsi;
2192c2c66affSColin Finck     BOOL is_wow64;
2193c2c66affSColin Finck 
2194c2c66affSColin Finck     if (!pGetNativeSystemInfo)
2195c2c66affSColin Finck     {
2196c2c66affSColin Finck         win_skip("GetNativeSystemInfo is not available\n");
2197c2c66affSColin Finck         return;
2198c2c66affSColin Finck     }
2199c2c66affSColin Finck 
2200c2c66affSColin Finck     if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
2201c2c66affSColin Finck 
2202c2c66affSColin Finck     GetSystemInfo(&si);
2203c2c66affSColin Finck     pGetNativeSystemInfo(&nsi);
2204c2c66affSColin Finck     if (is_wow64)
2205c2c66affSColin Finck     {
2206c2c66affSColin Finck         if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
2207c2c66affSColin Finck         {
2208c2c66affSColin Finck             ok(S(U(nsi)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64,
2209c2c66affSColin Finck                "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2210c2c66affSColin Finck                S(U(nsi)).wProcessorArchitecture);
2211c2c66affSColin Finck             ok(nsi.dwProcessorType == PROCESSOR_AMD_X8664,
2212c2c66affSColin Finck                "Expected PROCESSOR_AMD_X8664, got %d\n",
2213c2c66affSColin Finck                nsi.dwProcessorType);
2214c2c66affSColin Finck         }
2215c2c66affSColin Finck     }
2216c2c66affSColin Finck     else
2217c2c66affSColin Finck     {
2218c2c66affSColin Finck         ok(S(U(si)).wProcessorArchitecture == S(U(nsi)).wProcessorArchitecture,
2219c2c66affSColin Finck            "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2220c2c66affSColin Finck            S(U(si)).wProcessorArchitecture, S(U(nsi)).wProcessorArchitecture);
2221c2c66affSColin Finck         ok(si.dwProcessorType == nsi.dwProcessorType,
2222c2c66affSColin Finck            "Expected no difference for dwProcessorType, got %d and %d\n",
2223c2c66affSColin Finck            si.dwProcessorType, nsi.dwProcessorType);
2224c2c66affSColin Finck     }
2225c2c66affSColin Finck }
2226c2c66affSColin Finck 
test_RegistryQuota(void)2227c2c66affSColin Finck static void test_RegistryQuota(void)
2228c2c66affSColin Finck {
2229c2c66affSColin Finck     BOOL ret;
2230c2c66affSColin Finck     DWORD max_quota, used_quota;
2231c2c66affSColin Finck 
2232c2c66affSColin Finck     if (!pGetSystemRegistryQuota)
2233c2c66affSColin Finck     {
2234c2c66affSColin Finck         win_skip("GetSystemRegistryQuota is not available\n");
2235c2c66affSColin Finck         return;
2236c2c66affSColin Finck     }
2237c2c66affSColin Finck 
2238c2c66affSColin Finck     ret = pGetSystemRegistryQuota(NULL, NULL);
2239c2c66affSColin Finck     ok(ret == TRUE,
2240c2c66affSColin Finck        "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2241c2c66affSColin Finck 
2242c2c66affSColin Finck     ret = pGetSystemRegistryQuota(&max_quota, NULL);
2243c2c66affSColin Finck     ok(ret == TRUE,
2244c2c66affSColin Finck        "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2245c2c66affSColin Finck 
2246c2c66affSColin Finck     ret = pGetSystemRegistryQuota(NULL, &used_quota);
2247c2c66affSColin Finck     ok(ret == TRUE,
2248c2c66affSColin Finck        "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2249c2c66affSColin Finck 
2250c2c66affSColin Finck     ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
2251c2c66affSColin Finck     ok(ret == TRUE,
2252c2c66affSColin Finck        "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
2253c2c66affSColin Finck }
2254c2c66affSColin Finck 
test_TerminateProcess(void)2255c2c66affSColin Finck static void test_TerminateProcess(void)
2256c2c66affSColin Finck {
2257c2c66affSColin Finck     static char cmdline[] = "winver.exe";
2258c2c66affSColin Finck     PROCESS_INFORMATION pi;
2259c2c66affSColin Finck     STARTUPINFOA si;
2260c2c66affSColin Finck     DWORD ret;
2261c2c66affSColin Finck     HANDLE dummy, thread;
2262c2c66affSColin Finck 
2263c2c66affSColin Finck     memset(&si, 0, sizeof(si));
2264c2c66affSColin Finck     si.cb = sizeof(si);
2265c2c66affSColin Finck     SetLastError(0xdeadbeef);
2266c2c66affSColin Finck     ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
2267c2c66affSColin Finck     ok(ret, "CreateProcess error %u\n", GetLastError());
2268c2c66affSColin Finck 
2269c2c66affSColin Finck     SetLastError(0xdeadbeef);
2270c2c66affSColin Finck     thread = CreateRemoteThread(pi.hProcess, NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret);
2271c2c66affSColin Finck     ok(thread != 0, "CreateRemoteThread error %d\n", GetLastError());
2272c2c66affSColin Finck 
2273c2c66affSColin Finck     /* create a not closed thread handle duplicate in the target process */
2274c2c66affSColin Finck     SetLastError(0xdeadbeef);
2275c2c66affSColin Finck     ret = DuplicateHandle(GetCurrentProcess(), thread, pi.hProcess, &dummy,
2276c2c66affSColin Finck                           0, FALSE, DUPLICATE_SAME_ACCESS);
2277c2c66affSColin Finck     ok(ret, "DuplicateHandle error %u\n", GetLastError());
2278c2c66affSColin Finck 
2279c2c66affSColin Finck     SetLastError(0xdeadbeef);
2280c2c66affSColin Finck     ret = TerminateThread(thread, 0);
2281c2c66affSColin Finck     ok(ret, "TerminateThread error %u\n", GetLastError());
2282c2c66affSColin Finck     CloseHandle(thread);
2283c2c66affSColin Finck 
2284c2c66affSColin Finck     SetLastError(0xdeadbeef);
2285c2c66affSColin Finck     ret = TerminateProcess(pi.hProcess, 0);
2286c2c66affSColin Finck     ok(ret, "TerminateProcess error %u\n", GetLastError());
2287c2c66affSColin Finck 
2288c2c66affSColin Finck     CloseHandle(pi.hProcess);
2289c2c66affSColin Finck     CloseHandle(pi.hThread);
2290c2c66affSColin Finck }
2291c2c66affSColin Finck 
test_DuplicateHandle(void)2292c2c66affSColin Finck static void test_DuplicateHandle(void)
2293c2c66affSColin Finck {
2294c2c66affSColin Finck     char path[MAX_PATH], file_name[MAX_PATH];
2295c2c66affSColin Finck     HANDLE f, fmin, out;
2296c2c66affSColin Finck     DWORD info;
2297c2c66affSColin Finck     BOOL r;
2298c2c66affSColin Finck 
2299c2c66affSColin Finck     r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2300c2c66affSColin Finck             GetCurrentProcess(), &out, 0, FALSE,
2301c2c66affSColin Finck             DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2302c2c66affSColin Finck     ok(r, "DuplicateHandle error %u\n", GetLastError());
2303c2c66affSColin Finck     r = GetHandleInformation(out, &info);
2304c2c66affSColin Finck     ok(r, "GetHandleInformation error %u\n", GetLastError());
2305c2c66affSColin Finck     ok(info == 0, "info = %x\n", info);
2306c2c66affSColin Finck     ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2307c2c66affSColin Finck     CloseHandle(out);
2308c2c66affSColin Finck 
2309c2c66affSColin Finck     r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2310c2c66affSColin Finck             GetCurrentProcess(), &out, 0, TRUE,
2311c2c66affSColin Finck             DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2312c2c66affSColin Finck     ok(r, "DuplicateHandle error %u\n", GetLastError());
2313c2c66affSColin Finck     r = GetHandleInformation(out, &info);
2314c2c66affSColin Finck     ok(r, "GetHandleInformation error %u\n", GetLastError());
2315c2c66affSColin Finck     ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2316c2c66affSColin Finck     ok(out != GetCurrentProcess(), "out = GetCurrentProcess()\n");
2317c2c66affSColin Finck     CloseHandle(out);
2318c2c66affSColin Finck 
2319c2c66affSColin Finck     GetTempPathA(MAX_PATH, path);
2320c2c66affSColin Finck     GetTempFileNameA(path, "wt", 0, file_name);
2321c2c66affSColin Finck     f = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2322c2c66affSColin Finck     if (f == INVALID_HANDLE_VALUE)
2323c2c66affSColin Finck     {
2324c2c66affSColin Finck         ok(0, "could not create %s\n", file_name);
2325c2c66affSColin Finck         return;
2326c2c66affSColin Finck     }
2327c2c66affSColin Finck 
2328c2c66affSColin Finck     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2329c2c66affSColin Finck             0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2330c2c66affSColin Finck     ok(r, "DuplicateHandle error %u\n", GetLastError());
2331c2c66affSColin Finck     ok(f == out, "f != out\n");
2332c2c66affSColin Finck     r = GetHandleInformation(out, &info);
2333c2c66affSColin Finck     ok(r, "GetHandleInformation error %u\n", GetLastError());
2334c2c66affSColin Finck     ok(info == 0, "info = %x\n", info);
2335c2c66affSColin Finck 
2336c2c66affSColin Finck     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2337c2c66affSColin Finck             0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2338c2c66affSColin Finck     ok(r, "DuplicateHandle error %u\n", GetLastError());
2339c2c66affSColin Finck     ok(f == out, "f != out\n");
2340c2c66affSColin Finck     r = GetHandleInformation(out, &info);
2341c2c66affSColin Finck     ok(r, "GetHandleInformation error %u\n", GetLastError());
2342c2c66affSColin Finck     ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2343c2c66affSColin Finck 
2344c2c66affSColin Finck     r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
2345c2c66affSColin Finck     ok(r, "SetHandleInformation error %u\n", GetLastError());
2346c2c66affSColin Finck     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2347c2c66affSColin Finck                 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2348c2c66affSColin Finck     ok(r, "DuplicateHandle error %u\n", GetLastError());
2349c2c66affSColin Finck     ok(f != out, "f == out\n");
2350c2c66affSColin Finck     r = GetHandleInformation(out, &info);
2351c2c66affSColin Finck     ok(r, "GetHandleInformation error %u\n", GetLastError());
2352c2c66affSColin Finck     ok(info == HANDLE_FLAG_INHERIT, "info = %x\n", info);
2353c2c66affSColin Finck     r = SetHandleInformation(f, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
2354c2c66affSColin Finck     ok(r, "SetHandleInformation error %u\n", GetLastError());
2355c2c66affSColin Finck 
2356c2c66affSColin Finck     /* Test if DuplicateHandle allocates first free handle */
2357c2c66affSColin Finck     if (f > out)
2358c2c66affSColin Finck     {
2359c2c66affSColin Finck         fmin = out;
2360c2c66affSColin Finck     }
2361c2c66affSColin Finck     else
2362c2c66affSColin Finck     {
2363c2c66affSColin Finck         fmin = f;
2364c2c66affSColin Finck         f = out;
2365c2c66affSColin Finck     }
2366c2c66affSColin Finck     CloseHandle(fmin);
2367c2c66affSColin Finck     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2368c2c66affSColin Finck             0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2369c2c66affSColin Finck     ok(r, "DuplicateHandle error %u\n", GetLastError());
2370c2c66affSColin Finck     ok(f == out, "f != out\n");
2371c2c66affSColin Finck     CloseHandle(out);
2372c2c66affSColin Finck     DeleteFileA(file_name);
2373c2c66affSColin Finck 
2374c2c66affSColin Finck     f = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
2375c2c66affSColin Finck     if (!is_console(f))
2376c2c66affSColin Finck     {
2377c2c66affSColin Finck         skip("DuplicateHandle on console handle\n");
2378c2c66affSColin Finck         CloseHandle(f);
2379c2c66affSColin Finck         return;
2380c2c66affSColin Finck     }
2381c2c66affSColin Finck 
2382c2c66affSColin Finck     r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out,
2383c2c66affSColin Finck             0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
2384c2c66affSColin Finck     ok(r, "DuplicateHandle error %u\n", GetLastError());
2385c2c66affSColin Finck     todo_wine ok(f != out, "f == out\n");
2386c2c66affSColin Finck     CloseHandle(out);
2387c2c66affSColin Finck }
2388c2c66affSColin Finck 
2389c2c66affSColin Finck #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
_test_completion(int line,HANDLE port,DWORD ekey,ULONG_PTR evalue,ULONG_PTR eoverlapped,DWORD wait)2390c2c66affSColin Finck static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait)
2391c2c66affSColin Finck {
2392c2c66affSColin Finck     LPOVERLAPPED overlapped;
2393c2c66affSColin Finck     ULONG_PTR value;
2394c2c66affSColin Finck     DWORD key;
2395c2c66affSColin Finck     BOOL ret;
2396c2c66affSColin Finck 
2397c2c66affSColin Finck     ret = GetQueuedCompletionStatus(port, &key, &value, &overlapped, wait);
2398c2c66affSColin Finck 
2399c2c66affSColin Finck     ok_(__FILE__, line)(ret, "GetQueuedCompletionStatus: %x\n", GetLastError());
2400c2c66affSColin Finck     if (ret)
2401c2c66affSColin Finck     {
2402c2c66affSColin Finck         ok_(__FILE__, line)(key == ekey, "unexpected key %x\n", key);
2403c2c66affSColin Finck         ok_(__FILE__, line)(value == evalue, "unexpected value %p\n", (void *)value);
2404c2c66affSColin Finck         ok_(__FILE__, line)(overlapped == (LPOVERLAPPED)eoverlapped, "unexpected overlapped %p\n", overlapped);
2405c2c66affSColin Finck     }
2406c2c66affSColin Finck }
2407c2c66affSColin Finck 
2408c2c66affSColin Finck #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
_create_process(int line,const char * command,LPPROCESS_INFORMATION pi)2409c2c66affSColin Finck static void _create_process(int line, const char *command, LPPROCESS_INFORMATION pi)
2410c2c66affSColin Finck {
2411c2c66affSColin Finck     BOOL ret;
2412c2c66affSColin Finck     char buffer[MAX_PATH];
2413c2c66affSColin Finck     STARTUPINFOA si = {0};
2414c2c66affSColin Finck 
2415c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c %s", selfname, command);
2416c2c66affSColin Finck 
2417c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
2418c2c66affSColin Finck     ok_(__FILE__, line)(ret, "CreateProcess error %u\n", GetLastError());
2419c2c66affSColin Finck }
2420c2c66affSColin Finck 
2421ed41a4deSAmine Khaldi #define test_assigned_proc(job, ...) _test_assigned_proc(__LINE__, job, __VA_ARGS__)
_test_assigned_proc(int line,HANDLE job,int expected_count,...)2422ed41a4deSAmine Khaldi static void _test_assigned_proc(int line, HANDLE job, int expected_count, ...)
2423ed41a4deSAmine Khaldi {
2424ed41a4deSAmine Khaldi     char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 20];
2425ed41a4deSAmine Khaldi     PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2426ed41a4deSAmine Khaldi     DWORD ret_len, pid;
2427ed41a4deSAmine Khaldi     va_list valist;
2428ed41a4deSAmine Khaldi     int n;
2429ed41a4deSAmine Khaldi     BOOL ret;
2430ed41a4deSAmine Khaldi 
2431ed41a4deSAmine Khaldi     memset(buf, 0, sizeof(buf));
2432ed41a4deSAmine Khaldi     ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2433ed41a4deSAmine Khaldi     ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2434ed41a4deSAmine Khaldi     if (ret)
2435ed41a4deSAmine Khaldi     {
2436ed41a4deSAmine Khaldi         todo_wine_if(expected_count)
2437ed41a4deSAmine Khaldi         ok_(__FILE__, line)(expected_count == pid_list->NumberOfAssignedProcesses,
2438ed41a4deSAmine Khaldi                             "Expected NumberOfAssignedProcesses to be %d (expected_count) is %d\n",
2439ed41a4deSAmine Khaldi                             expected_count, pid_list->NumberOfAssignedProcesses);
2440ed41a4deSAmine Khaldi         todo_wine_if(expected_count)
2441ed41a4deSAmine Khaldi         ok_(__FILE__, line)(expected_count == pid_list->NumberOfProcessIdsInList,
2442ed41a4deSAmine Khaldi                             "Expected NumberOfProcessIdsInList to be %d (expected_count) is %d\n",
2443ed41a4deSAmine Khaldi                             expected_count, pid_list->NumberOfProcessIdsInList);
2444ed41a4deSAmine Khaldi 
2445ed41a4deSAmine Khaldi         va_start(valist, expected_count);
2446ed41a4deSAmine Khaldi         for (n = 0; n < min(expected_count, pid_list->NumberOfProcessIdsInList); ++n)
2447ed41a4deSAmine Khaldi         {
2448ed41a4deSAmine Khaldi             pid = va_arg(valist, DWORD);
2449ed41a4deSAmine Khaldi             ok_(__FILE__, line)(pid == pid_list->ProcessIdList[n],
2450ed41a4deSAmine Khaldi                                 "Expected pid_list->ProcessIdList[%d] to be %x is %lx\n",
2451ed41a4deSAmine Khaldi                                 n, pid, pid_list->ProcessIdList[n]);
2452ed41a4deSAmine Khaldi         }
2453ed41a4deSAmine Khaldi         va_end(valist);
2454ed41a4deSAmine Khaldi     }
2455ed41a4deSAmine Khaldi }
2456ed41a4deSAmine Khaldi 
2457ed41a4deSAmine Khaldi #define test_accounting(job, total_proc, active_proc, terminated_proc) _test_accounting(__LINE__, job, total_proc, active_proc, terminated_proc)
_test_accounting(int line,HANDLE job,int total_proc,int active_proc,int terminated_proc)2458ed41a4deSAmine Khaldi static void _test_accounting(int line, HANDLE job, int total_proc, int active_proc, int terminated_proc)
2459ed41a4deSAmine Khaldi {
2460ed41a4deSAmine Khaldi     JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basic_accounting;
2461ed41a4deSAmine Khaldi     DWORD ret_len;
2462ed41a4deSAmine Khaldi     BOOL ret;
2463ed41a4deSAmine Khaldi 
2464ed41a4deSAmine Khaldi     memset(&basic_accounting, 0, sizeof(basic_accounting));
2465ed41a4deSAmine Khaldi     ret = pQueryInformationJobObject(job, JobObjectBasicAccountingInformation, &basic_accounting, sizeof(basic_accounting), &ret_len);
2466ed41a4deSAmine Khaldi     ok_(__FILE__, line)(ret, "QueryInformationJobObject error %u\n", GetLastError());
2467ed41a4deSAmine Khaldi     if (ret)
2468ed41a4deSAmine Khaldi     {
2469ed41a4deSAmine Khaldi         /* Not going to check process times or page faults */
2470ed41a4deSAmine Khaldi 
2471ed41a4deSAmine Khaldi         todo_wine_if(total_proc)
2472ed41a4deSAmine Khaldi         ok_(__FILE__, line)(total_proc == basic_accounting.TotalProcesses,
2473ed41a4deSAmine Khaldi                             "Expected basic_accounting.TotalProcesses to be %d (total_proc) is %d\n",
2474ed41a4deSAmine Khaldi                             total_proc, basic_accounting.TotalProcesses);
2475ed41a4deSAmine Khaldi         todo_wine_if(active_proc)
2476ed41a4deSAmine Khaldi         ok_(__FILE__, line)(active_proc == basic_accounting.ActiveProcesses,
2477ed41a4deSAmine Khaldi                             "Expected basic_accounting.ActiveProcesses to be %d (active_proc) is %d\n",
2478ed41a4deSAmine Khaldi                             active_proc, basic_accounting.ActiveProcesses);
2479ed41a4deSAmine Khaldi         ok_(__FILE__, line)(terminated_proc == basic_accounting.TotalTerminatedProcesses,
2480ed41a4deSAmine Khaldi                             "Expected basic_accounting.TotalTerminatedProcesses to be %d (terminated_proc) is %d\n",
2481ed41a4deSAmine Khaldi                             terminated_proc, basic_accounting.TotalTerminatedProcesses);
2482ed41a4deSAmine Khaldi     }
2483ed41a4deSAmine Khaldi }
2484c2c66affSColin Finck 
test_IsProcessInJob(void)2485c2c66affSColin Finck static void test_IsProcessInJob(void)
2486c2c66affSColin Finck {
2487c2c66affSColin Finck     HANDLE job, job2;
2488c2c66affSColin Finck     PROCESS_INFORMATION pi;
2489c2c66affSColin Finck     BOOL ret, out;
2490c2c66affSColin Finck     DWORD dwret;
2491c2c66affSColin Finck 
2492c2c66affSColin Finck     if (!pIsProcessInJob)
2493c2c66affSColin Finck     {
2494c2c66affSColin Finck         win_skip("IsProcessInJob not available.\n");
2495c2c66affSColin Finck         return;
2496c2c66affSColin Finck     }
2497c2c66affSColin Finck 
2498c2c66affSColin Finck     job = pCreateJobObjectW(NULL, NULL);
2499c2c66affSColin Finck     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2500c2c66affSColin Finck 
2501c2c66affSColin Finck     job2 = pCreateJobObjectW(NULL, NULL);
2502c2c66affSColin Finck     ok(job2 != NULL, "CreateJobObject error %u\n", GetLastError());
2503c2c66affSColin Finck 
2504c2c66affSColin Finck     create_process("wait", &pi);
2505c2c66affSColin Finck 
2506c2c66affSColin Finck     out = TRUE;
2507c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, job, &out);
2508c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2509c2c66affSColin Finck     ok(!out, "IsProcessInJob returned out=%u\n", out);
2510ed41a4deSAmine Khaldi     test_assigned_proc(job, 0);
2511ed41a4deSAmine Khaldi     test_accounting(job, 0, 0, 0);
2512c2c66affSColin Finck 
2513c2c66affSColin Finck     out = TRUE;
2514c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, job2, &out);
2515c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2516c2c66affSColin Finck     ok(!out, "IsProcessInJob returned out=%u\n", out);
2517ed41a4deSAmine Khaldi     test_assigned_proc(job2, 0);
2518ed41a4deSAmine Khaldi     test_accounting(job2, 0, 0, 0);
2519c2c66affSColin Finck 
2520c2c66affSColin Finck     out = TRUE;
2521c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2522c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2523c2c66affSColin Finck     ok(!out, "IsProcessInJob returned out=%u\n", out);
2524c2c66affSColin Finck 
2525c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi.hProcess);
2526c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2527c2c66affSColin Finck 
2528c2c66affSColin Finck     out = FALSE;
2529c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, job, &out);
2530c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2531c2c66affSColin Finck     ok(out, "IsProcessInJob returned out=%u\n", out);
2532ed41a4deSAmine Khaldi     test_assigned_proc(job, 1, pi.dwProcessId);
2533ed41a4deSAmine Khaldi     test_accounting(job, 1, 1, 0);
2534c2c66affSColin Finck 
2535c2c66affSColin Finck     out = TRUE;
2536c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, job2, &out);
2537c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2538c2c66affSColin Finck     ok(!out, "IsProcessInJob returned out=%u\n", out);
2539ed41a4deSAmine Khaldi     test_assigned_proc(job2, 0);
2540ed41a4deSAmine Khaldi     test_accounting(job2, 0, 0, 0);
2541c2c66affSColin Finck 
2542c2c66affSColin Finck     out = FALSE;
2543c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, NULL, &out);
2544c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2545c2c66affSColin Finck     ok(out, "IsProcessInJob returned out=%u\n", out);
2546c2c66affSColin Finck 
2547c2c66affSColin Finck     TerminateProcess(pi.hProcess, 0);
2548c2c66affSColin Finck 
2549c2c66affSColin Finck     dwret = WaitForSingleObject(pi.hProcess, 1000);
2550c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2551c2c66affSColin Finck 
2552c2c66affSColin Finck     out = FALSE;
2553c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, job, &out);
2554c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2555c2c66affSColin Finck     ok(out, "IsProcessInJob returned out=%u\n", out);
2556ed41a4deSAmine Khaldi     test_assigned_proc(job, 0);
2557ed41a4deSAmine Khaldi     test_accounting(job, 1, 0, 0);
2558c2c66affSColin Finck 
2559c2c66affSColin Finck     CloseHandle(pi.hProcess);
2560c2c66affSColin Finck     CloseHandle(pi.hThread);
2561c2c66affSColin Finck     CloseHandle(job);
2562c2c66affSColin Finck     CloseHandle(job2);
2563c2c66affSColin Finck }
2564c2c66affSColin Finck 
test_TerminateJobObject(void)2565c2c66affSColin Finck static void test_TerminateJobObject(void)
2566c2c66affSColin Finck {
2567c2c66affSColin Finck     HANDLE job;
2568c2c66affSColin Finck     PROCESS_INFORMATION pi;
2569c2c66affSColin Finck     BOOL ret;
2570c2c66affSColin Finck     DWORD dwret;
2571c2c66affSColin Finck 
2572c2c66affSColin Finck     job = pCreateJobObjectW(NULL, NULL);
2573c2c66affSColin Finck     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2574ed41a4deSAmine Khaldi     test_assigned_proc(job, 0);
2575ed41a4deSAmine Khaldi     test_accounting(job, 0, 0, 0);
2576c2c66affSColin Finck 
2577c2c66affSColin Finck     create_process("wait", &pi);
2578c2c66affSColin Finck 
2579c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi.hProcess);
2580c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2581ed41a4deSAmine Khaldi     test_assigned_proc(job, 1, pi.dwProcessId);
2582ed41a4deSAmine Khaldi     test_accounting(job, 1, 1, 0);
2583c2c66affSColin Finck 
2584c2c66affSColin Finck     ret = pTerminateJobObject(job, 123);
2585c2c66affSColin Finck     ok(ret, "TerminateJobObject error %u\n", GetLastError());
2586c2c66affSColin Finck 
2587c2c66affSColin Finck     dwret = WaitForSingleObject(pi.hProcess, 1000);
2588c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2589c2c66affSColin Finck     if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2590ed41a4deSAmine Khaldi     test_assigned_proc(job, 0);
2591ed41a4deSAmine Khaldi     test_accounting(job, 1, 0, 0);
2592c2c66affSColin Finck 
2593c2c66affSColin Finck     ret = GetExitCodeProcess(pi.hProcess, &dwret);
2594c2c66affSColin Finck     ok(ret, "GetExitCodeProcess error %u\n", GetLastError());
2595e26c8bc6STimo Kreuzer     ok(dwret == 123 || broken(dwret == 0) || broken(dwret == 259) /* randomly fails on Win 2000 / XP */,
2596c2c66affSColin Finck        "wrong exitcode %u\n", dwret);
2597c2c66affSColin Finck 
2598c2c66affSColin Finck     CloseHandle(pi.hProcess);
2599c2c66affSColin Finck     CloseHandle(pi.hThread);
2600c2c66affSColin Finck 
2601c2c66affSColin Finck     /* Test adding an already terminated process to a job object */
2602c2c66affSColin Finck     create_process("exit", &pi);
2603c2c66affSColin Finck 
2604c2c66affSColin Finck     dwret = WaitForSingleObject(pi.hProcess, 1000);
2605c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2606c2c66affSColin Finck 
2607c2c66affSColin Finck     SetLastError(0xdeadbeef);
2608c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi.hProcess);
2609c2c66affSColin Finck     ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n");
2610c2c66affSColin Finck     expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2611ed41a4deSAmine Khaldi     test_assigned_proc(job, 0);
2612ed41a4deSAmine Khaldi     test_accounting(job, 1, 0, 0);
2613c2c66affSColin Finck 
2614c2c66affSColin Finck     CloseHandle(pi.hProcess);
2615c2c66affSColin Finck     CloseHandle(pi.hThread);
2616c2c66affSColin Finck 
2617c2c66affSColin Finck     CloseHandle(job);
2618c2c66affSColin Finck }
2619c2c66affSColin Finck 
test_QueryInformationJobObject(void)2620c2c66affSColin Finck static void test_QueryInformationJobObject(void)
2621c2c66affSColin Finck {
2622c2c66affSColin Finck     char buf[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 4];
2623c2c66affSColin Finck     PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)buf;
2624c2c66affSColin Finck     JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info;
2625c2c66affSColin Finck     JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit_info = &ext_limit_info.BasicLimitInformation;
2626c2c66affSColin Finck     DWORD dwret, ret_len;
2627c2c66affSColin Finck     PROCESS_INFORMATION pi[2];
2628c2c66affSColin Finck     HANDLE job;
2629c2c66affSColin Finck     BOOL ret;
2630c2c66affSColin Finck 
2631c2c66affSColin Finck     job = pCreateJobObjectW(NULL, NULL);
2632c2c66affSColin Finck     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2633c2c66affSColin Finck 
2634c2c66affSColin Finck     /* Only active processes are returned */
2635c2c66affSColin Finck     create_process("exit", &pi[0]);
2636c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2637c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2638c2c66affSColin Finck     dwret = WaitForSingleObject(pi[0].hProcess, 1000);
2639c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2640c2c66affSColin Finck 
2641c2c66affSColin Finck     CloseHandle(pi[0].hProcess);
2642c2c66affSColin Finck     CloseHandle(pi[0].hThread);
2643c2c66affSColin Finck 
2644c2c66affSColin Finck     create_process("wait", &pi[0]);
2645c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi[0].hProcess);
2646c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2647c2c66affSColin Finck 
2648c2c66affSColin Finck     create_process("wait", &pi[1]);
2649c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi[1].hProcess);
2650c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2651c2c66affSColin Finck 
2652c2c66affSColin Finck     SetLastError(0xdeadbeef);
2653c2c66affSColin Finck     ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2654c2c66affSColin Finck                                     FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len);
2655c2c66affSColin Finck     ok(!ret, "QueryInformationJobObject expected failure\n");
2656c2c66affSColin Finck     expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2657c2c66affSColin Finck 
2658c2c66affSColin Finck     SetLastError(0xdeadbeef);
2659c2c66affSColin Finck     memset(buf, 0, sizeof(buf));
2660c2c66affSColin Finck     pid_list->NumberOfAssignedProcesses = 42;
2661c2c66affSColin Finck     pid_list->NumberOfProcessIdsInList  = 42;
2662c2c66affSColin Finck     ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
2663c2c66affSColin Finck                                     FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len);
2664c2c66affSColin Finck     todo_wine
2665c2c66affSColin Finck     ok(!ret, "QueryInformationJobObject expected failure\n");
2666c2c66affSColin Finck     todo_wine
2667c2c66affSColin Finck     expect_eq_d(ERROR_MORE_DATA, GetLastError());
2668c2c66affSColin Finck     if (ret)
2669c2c66affSColin Finck     {
2670c2c66affSColin Finck         todo_wine
2671c2c66affSColin Finck         expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
2672c2c66affSColin Finck         todo_wine
2673c2c66affSColin Finck         expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
2674c2c66affSColin Finck     }
2675c2c66affSColin Finck 
2676c2c66affSColin Finck     memset(buf, 0, sizeof(buf));
2677c2c66affSColin Finck     ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
2678c2c66affSColin Finck     ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2679c2c66affSColin Finck     if(ret)
2680c2c66affSColin Finck     {
2681c2c66affSColin Finck         if (pid_list->NumberOfAssignedProcesses == 3) /* Win 8 */
2682c2c66affSColin Finck             win_skip("Number of assigned processes broken on Win 8\n");
2683c2c66affSColin Finck         else
2684c2c66affSColin Finck         {
2685c2c66affSColin Finck             ULONG_PTR *list = pid_list->ProcessIdList;
2686c2c66affSColin Finck 
2687c2c66affSColin Finck             todo_wine
2688c2c66affSColin Finck             ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]),
2689c2c66affSColin Finck                "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2690c2c66affSColin Finck 
2691c2c66affSColin Finck             todo_wine
2692c2c66affSColin Finck             expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
2693c2c66affSColin Finck             todo_wine
2694c2c66affSColin Finck             expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
2695c2c66affSColin Finck             todo_wine
2696c2c66affSColin Finck             expect_eq_d(pi[0].dwProcessId, list[0]);
2697c2c66affSColin Finck             todo_wine
2698c2c66affSColin Finck             expect_eq_d(pi[1].dwProcessId, list[1]);
2699c2c66affSColin Finck         }
2700c2c66affSColin Finck     }
2701c2c66affSColin Finck 
2702c2c66affSColin Finck     /* test JobObjectBasicLimitInformation */
2703c2c66affSColin Finck     ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2704c2c66affSColin Finck                                      sizeof(*basic_limit_info) - 1, &ret_len);
2705c2c66affSColin Finck     ok(!ret, "QueryInformationJobObject expected failure\n");
2706c2c66affSColin Finck     expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2707c2c66affSColin Finck 
2708c2c66affSColin Finck     ret_len = 0xdeadbeef;
2709c2c66affSColin Finck     memset(basic_limit_info, 0x11, sizeof(*basic_limit_info));
2710c2c66affSColin Finck     ret = pQueryInformationJobObject(job, JobObjectBasicLimitInformation, basic_limit_info,
2711c2c66affSColin Finck                                      sizeof(*basic_limit_info), &ret_len);
2712c2c66affSColin Finck     ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2713c2c66affSColin Finck     ok(ret_len == sizeof(*basic_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2714c2c66affSColin Finck     expect_eq_d(0, basic_limit_info->LimitFlags);
2715c2c66affSColin Finck 
2716c2c66affSColin Finck     /* test JobObjectExtendedLimitInformation */
2717c2c66affSColin Finck     ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2718c2c66affSColin Finck                                      sizeof(ext_limit_info) - 1, &ret_len);
2719c2c66affSColin Finck     ok(!ret, "QueryInformationJobObject expected failure\n");
2720c2c66affSColin Finck     expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
2721c2c66affSColin Finck 
2722c2c66affSColin Finck     ret_len = 0xdeadbeef;
2723c2c66affSColin Finck     memset(&ext_limit_info, 0x11, sizeof(ext_limit_info));
2724c2c66affSColin Finck     ret = pQueryInformationJobObject(job, JobObjectExtendedLimitInformation, &ext_limit_info,
2725c2c66affSColin Finck                                      sizeof(ext_limit_info), &ret_len);
2726c2c66affSColin Finck     ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
2727c2c66affSColin Finck     ok(ret_len == sizeof(ext_limit_info), "QueryInformationJobObject returned ret_len=%u\n", ret_len);
2728c2c66affSColin Finck     expect_eq_d(0, basic_limit_info->LimitFlags);
2729c2c66affSColin Finck 
2730c2c66affSColin Finck     TerminateProcess(pi[0].hProcess, 0);
2731c2c66affSColin Finck     CloseHandle(pi[0].hProcess);
2732c2c66affSColin Finck     CloseHandle(pi[0].hThread);
2733c2c66affSColin Finck 
2734c2c66affSColin Finck     TerminateProcess(pi[1].hProcess, 0);
2735c2c66affSColin Finck     CloseHandle(pi[1].hProcess);
2736c2c66affSColin Finck     CloseHandle(pi[1].hThread);
2737c2c66affSColin Finck 
2738c2c66affSColin Finck     CloseHandle(job);
2739c2c66affSColin Finck }
2740c2c66affSColin Finck 
test_CompletionPort(void)2741c2c66affSColin Finck static void test_CompletionPort(void)
2742c2c66affSColin Finck {
2743c2c66affSColin Finck     JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
2744c2c66affSColin Finck     PROCESS_INFORMATION pi;
2745c2c66affSColin Finck     HANDLE job, port;
2746c2c66affSColin Finck     DWORD dwret;
2747c2c66affSColin Finck     BOOL ret;
2748c2c66affSColin Finck 
2749c2c66affSColin Finck     job = pCreateJobObjectW(NULL, NULL);
2750c2c66affSColin Finck     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2751c2c66affSColin Finck 
2752c2c66affSColin Finck     port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
2753c2c66affSColin Finck     ok(port != NULL, "CreateIoCompletionPort error %u\n", GetLastError());
2754c2c66affSColin Finck 
2755c2c66affSColin Finck     port_info.CompletionKey = job;
2756c2c66affSColin Finck     port_info.CompletionPort = port;
2757c2c66affSColin Finck     ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info));
2758c2c66affSColin Finck     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2759c2c66affSColin Finck 
2760c2c66affSColin Finck     create_process("wait", &pi);
2761c2c66affSColin Finck 
2762c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi.hProcess);
2763c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2764c2c66affSColin Finck 
2765c2c66affSColin Finck     test_completion(port, JOB_OBJECT_MSG_NEW_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2766c2c66affSColin Finck 
2767c2c66affSColin Finck     TerminateProcess(pi.hProcess, 0);
2768c2c66affSColin Finck     dwret = WaitForSingleObject(pi.hProcess, 1000);
2769c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2770c2c66affSColin Finck 
2771c2c66affSColin Finck     test_completion(port, JOB_OBJECT_MSG_EXIT_PROCESS, (DWORD_PTR)job, pi.dwProcessId, 0);
2772c2c66affSColin Finck     test_completion(port, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, (DWORD_PTR)job, 0, 100);
2773c2c66affSColin Finck 
2774c2c66affSColin Finck     CloseHandle(pi.hProcess);
2775c2c66affSColin Finck     CloseHandle(pi.hThread);
2776c2c66affSColin Finck     CloseHandle(job);
2777c2c66affSColin Finck     CloseHandle(port);
2778c2c66affSColin Finck }
2779c2c66affSColin Finck 
test_KillOnJobClose(void)2780c2c66affSColin Finck static void test_KillOnJobClose(void)
2781c2c66affSColin Finck {
2782c2c66affSColin Finck     JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2783c2c66affSColin Finck     PROCESS_INFORMATION pi;
2784c2c66affSColin Finck     DWORD dwret;
2785c2c66affSColin Finck     HANDLE job;
2786c2c66affSColin Finck     BOOL ret;
2787c2c66affSColin Finck 
2788c2c66affSColin Finck     job = pCreateJobObjectW(NULL, NULL);
2789c2c66affSColin Finck     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2790c2c66affSColin Finck 
2791c2c66affSColin Finck     limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
2792c2c66affSColin Finck     ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2793c2c66affSColin Finck     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2794c2c66affSColin Finck     {
2795c2c66affSColin Finck         win_skip("Kill on job close limit not available\n");
2796c2c66affSColin Finck         return;
2797c2c66affSColin Finck     }
2798c2c66affSColin Finck     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2799ed41a4deSAmine Khaldi     test_assigned_proc(job, 0);
2800ed41a4deSAmine Khaldi     test_accounting(job, 0, 0, 0);
2801c2c66affSColin Finck 
2802c2c66affSColin Finck     create_process("wait", &pi);
2803c2c66affSColin Finck 
2804c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi.hProcess);
2805c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2806ed41a4deSAmine Khaldi     test_assigned_proc(job, 1, pi.dwProcessId);
2807ed41a4deSAmine Khaldi     test_accounting(job, 1, 1, 0);
2808c2c66affSColin Finck 
2809c2c66affSColin Finck     CloseHandle(job);
2810c2c66affSColin Finck 
2811c2c66affSColin Finck     dwret = WaitForSingleObject(pi.hProcess, 1000);
2812c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2813c2c66affSColin Finck     if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0);
2814c2c66affSColin Finck 
2815c2c66affSColin Finck     CloseHandle(pi.hProcess);
2816c2c66affSColin Finck     CloseHandle(pi.hThread);
2817c2c66affSColin Finck }
2818c2c66affSColin Finck 
test_WaitForJobObject(void)2819c2c66affSColin Finck static void test_WaitForJobObject(void)
2820c2c66affSColin Finck {
2821c2c66affSColin Finck     HANDLE job;
2822c2c66affSColin Finck     PROCESS_INFORMATION pi;
2823c2c66affSColin Finck     BOOL ret;
2824c2c66affSColin Finck     DWORD dwret;
2825c2c66affSColin Finck 
2826c2c66affSColin Finck     /* test waiting for a job object when the process is killed */
2827c2c66affSColin Finck     job = pCreateJobObjectW(NULL, NULL);
2828c2c66affSColin Finck     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2829c2c66affSColin Finck 
2830c2c66affSColin Finck     dwret = WaitForSingleObject(job, 100);
2831c2c66affSColin Finck     ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2832c2c66affSColin Finck 
2833c2c66affSColin Finck     create_process("wait", &pi);
2834c2c66affSColin Finck 
2835c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi.hProcess);
2836c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2837c2c66affSColin Finck 
2838c2c66affSColin Finck     dwret = WaitForSingleObject(job, 100);
2839c2c66affSColin Finck     ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2840c2c66affSColin Finck 
2841c2c66affSColin Finck     ret = pTerminateJobObject(job, 123);
2842c2c66affSColin Finck     ok(ret, "TerminateJobObject error %u\n", GetLastError());
2843c2c66affSColin Finck 
2844c2c66affSColin Finck     dwret = WaitForSingleObject(job, 500);
2845c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT),
2846c2c66affSColin Finck        "WaitForSingleObject returned %u\n", dwret);
2847c2c66affSColin Finck 
2848c2c66affSColin Finck     if (dwret == WAIT_TIMEOUT) /* Win 2000/XP */
2849c2c66affSColin Finck     {
2850c2c66affSColin Finck #ifdef __REACTOS__
2851c2c66affSColin Finck         if (!ret)
2852c2c66affSColin Finck         {
2853c2c66affSColin Finck             ok(0, "HACK: Killing process to speed up the test\n");
2854c2c66affSColin Finck             TerminateProcess(pi.hProcess, 0);
2855c2c66affSColin Finck         }
2856c2c66affSColin Finck #endif
2857c2c66affSColin Finck         CloseHandle(pi.hProcess);
2858c2c66affSColin Finck         CloseHandle(pi.hThread);
2859c2c66affSColin Finck         CloseHandle(job);
2860c2c66affSColin Finck         win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2861c2c66affSColin Finck         return;
2862c2c66affSColin Finck     }
2863c2c66affSColin Finck 
2864c2c66affSColin Finck     /* the object is not reset immediately */
2865c2c66affSColin Finck     dwret = WaitForSingleObject(job, 100);
2866c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2867c2c66affSColin Finck 
2868c2c66affSColin Finck     CloseHandle(pi.hProcess);
2869c2c66affSColin Finck     CloseHandle(pi.hThread);
2870c2c66affSColin Finck 
2871c2c66affSColin Finck     /* creating a new process doesn't reset the signalled state */
2872c2c66affSColin Finck     create_process("wait", &pi);
2873c2c66affSColin Finck 
2874c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi.hProcess);
2875c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2876c2c66affSColin Finck 
2877c2c66affSColin Finck     dwret = WaitForSingleObject(job, 100);
2878c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2879c2c66affSColin Finck 
2880c2c66affSColin Finck     ret = pTerminateJobObject(job, 123);
2881c2c66affSColin Finck     ok(ret, "TerminateJobObject error %u\n", GetLastError());
2882c2c66affSColin Finck 
2883c2c66affSColin Finck     CloseHandle(pi.hProcess);
2884c2c66affSColin Finck     CloseHandle(pi.hThread);
2885c2c66affSColin Finck 
2886c2c66affSColin Finck     CloseHandle(job);
2887c2c66affSColin Finck 
2888c2c66affSColin Finck     /* repeat the test, but this time the process terminates properly */
2889c2c66affSColin Finck     job = pCreateJobObjectW(NULL, NULL);
2890c2c66affSColin Finck     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2891c2c66affSColin Finck 
2892c2c66affSColin Finck     dwret = WaitForSingleObject(job, 100);
2893c2c66affSColin Finck     ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2894c2c66affSColin Finck 
2895c2c66affSColin Finck     create_process("exit", &pi);
2896c2c66affSColin Finck 
2897c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, pi.hProcess);
2898c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2899c2c66affSColin Finck 
2900c2c66affSColin Finck     dwret = WaitForSingleObject(job, 100);
2901c2c66affSColin Finck     ok(dwret == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", dwret);
2902c2c66affSColin Finck 
2903c2c66affSColin Finck     CloseHandle(pi.hProcess);
2904c2c66affSColin Finck     CloseHandle(pi.hThread);
2905c2c66affSColin Finck     CloseHandle(job);
2906c2c66affSColin Finck }
2907c2c66affSColin Finck 
test_AddSelfToJob(void)2908c2c66affSColin Finck static HANDLE test_AddSelfToJob(void)
2909c2c66affSColin Finck {
2910c2c66affSColin Finck     HANDLE job;
2911c2c66affSColin Finck     BOOL ret;
2912c2c66affSColin Finck 
2913c2c66affSColin Finck     job = pCreateJobObjectW(NULL, NULL);
2914c2c66affSColin Finck     ok(job != NULL, "CreateJobObject error %u\n", GetLastError());
2915c2c66affSColin Finck 
2916c2c66affSColin Finck     ret = pAssignProcessToJobObject(job, GetCurrentProcess());
2917c2c66affSColin Finck     ok(ret, "AssignProcessToJobObject error %u\n", GetLastError());
2918ed41a4deSAmine Khaldi     test_assigned_proc(job, 1, GetCurrentProcessId());
2919ed41a4deSAmine Khaldi     test_accounting(job, 1, 1, 0);
2920c2c66affSColin Finck 
2921c2c66affSColin Finck     return job;
2922c2c66affSColin Finck }
2923c2c66affSColin Finck 
test_jobInheritance(HANDLE job)2924c2c66affSColin Finck static void test_jobInheritance(HANDLE job)
2925c2c66affSColin Finck {
2926c2c66affSColin Finck     char buffer[MAX_PATH];
2927c2c66affSColin Finck     PROCESS_INFORMATION pi;
2928c2c66affSColin Finck     STARTUPINFOA si = {0};
2929c2c66affSColin Finck     DWORD dwret;
2930c2c66affSColin Finck     BOOL ret, out;
2931c2c66affSColin Finck 
2932c2c66affSColin Finck     if (!pIsProcessInJob)
2933c2c66affSColin Finck     {
2934c2c66affSColin Finck         win_skip("IsProcessInJob not available.\n");
2935c2c66affSColin Finck         return;
2936c2c66affSColin Finck     }
2937c2c66affSColin Finck 
2938c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2939c2c66affSColin Finck 
2940c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
2941c2c66affSColin Finck     ok(ret, "CreateProcessA error %u\n", GetLastError());
2942c2c66affSColin Finck 
2943c2c66affSColin Finck     out = FALSE;
2944c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, job, &out);
2945c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
2946c2c66affSColin Finck     ok(out, "IsProcessInJob returned out=%u\n", out);
2947ed41a4deSAmine Khaldi     test_assigned_proc(job, 2, GetCurrentProcessId(), pi.dwProcessId);
2948ed41a4deSAmine Khaldi     test_accounting(job, 2, 2, 0);
2949c2c66affSColin Finck 
2950c2c66affSColin Finck     dwret = WaitForSingleObject(pi.hProcess, 1000);
2951c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2952c2c66affSColin Finck 
2953c2c66affSColin Finck     CloseHandle(pi.hProcess);
2954c2c66affSColin Finck     CloseHandle(pi.hThread);
2955c2c66affSColin Finck }
2956c2c66affSColin Finck 
test_BreakawayOk(HANDLE job)2957c2c66affSColin Finck static void test_BreakawayOk(HANDLE job)
2958c2c66affSColin Finck {
2959c2c66affSColin Finck     JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
2960c2c66affSColin Finck     PROCESS_INFORMATION pi;
2961c2c66affSColin Finck     STARTUPINFOA si = {0};
2962c2c66affSColin Finck     char buffer[MAX_PATH];
2963c2c66affSColin Finck     BOOL ret, out;
2964c2c66affSColin Finck     DWORD dwret;
2965c2c66affSColin Finck 
2966c2c66affSColin Finck     if (!pIsProcessInJob)
2967c2c66affSColin Finck     {
2968c2c66affSColin Finck         win_skip("IsProcessInJob not available.\n");
2969c2c66affSColin Finck         return;
2970c2c66affSColin Finck     }
2971c2c66affSColin Finck 
2972c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c %s", selfname, "exit");
2973c2c66affSColin Finck 
2974c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2975c2c66affSColin Finck     ok(!ret, "CreateProcessA expected failure\n");
2976c2c66affSColin Finck     expect_eq_d(ERROR_ACCESS_DENIED, GetLastError());
2977ed41a4deSAmine Khaldi     test_assigned_proc(job, 1, GetCurrentProcessId());
2978ed41a4deSAmine Khaldi     test_accounting(job, 2, 1, 0);
2979c2c66affSColin Finck 
2980c2c66affSColin Finck     if (ret)
2981c2c66affSColin Finck     {
2982c2c66affSColin Finck         TerminateProcess(pi.hProcess, 0);
2983c2c66affSColin Finck 
2984c2c66affSColin Finck         dwret = WaitForSingleObject(pi.hProcess, 1000);
2985c2c66affSColin Finck         ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
2986c2c66affSColin Finck 
2987c2c66affSColin Finck         CloseHandle(pi.hProcess);
2988c2c66affSColin Finck         CloseHandle(pi.hThread);
2989c2c66affSColin Finck     }
2990c2c66affSColin Finck 
2991c2c66affSColin Finck     limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK;
2992c2c66affSColin Finck     ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
2993c2c66affSColin Finck     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
2994c2c66affSColin Finck 
2995c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
2996c2c66affSColin Finck     ok(ret, "CreateProcessA error %u\n", GetLastError());
2997c2c66affSColin Finck 
2998c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, job, &out);
2999c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
3000c2c66affSColin Finck     ok(!out, "IsProcessInJob returned out=%u\n", out);
3001ed41a4deSAmine Khaldi     test_assigned_proc(job, 1, GetCurrentProcessId());
3002ed41a4deSAmine Khaldi     test_accounting(job, 2, 1, 0);
3003c2c66affSColin Finck 
3004c2c66affSColin Finck     dwret = WaitForSingleObject(pi.hProcess, 1000);
3005c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
3006c2c66affSColin Finck 
3007c2c66affSColin Finck     CloseHandle(pi.hProcess);
3008c2c66affSColin Finck     CloseHandle(pi.hThread);
3009c2c66affSColin Finck 
3010c2c66affSColin Finck     limit_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
3011c2c66affSColin Finck     ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3012c2c66affSColin Finck     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
3013c2c66affSColin Finck 
3014c2c66affSColin Finck     ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3015c2c66affSColin Finck     ok(ret, "CreateProcess error %u\n", GetLastError());
3016c2c66affSColin Finck 
3017c2c66affSColin Finck     ret = pIsProcessInJob(pi.hProcess, job, &out);
3018c2c66affSColin Finck     ok(ret, "IsProcessInJob error %u\n", GetLastError());
3019c2c66affSColin Finck     ok(!out, "IsProcessInJob returned out=%u\n", out);
3020ed41a4deSAmine Khaldi     test_assigned_proc(job, 1, GetCurrentProcessId());
3021ed41a4deSAmine Khaldi     test_accounting(job, 2, 1, 0);
3022c2c66affSColin Finck 
3023c2c66affSColin Finck     dwret = WaitForSingleObject(pi.hProcess, 1000);
3024c2c66affSColin Finck     ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret);
3025c2c66affSColin Finck 
3026c2c66affSColin Finck     CloseHandle(pi.hProcess);
3027c2c66affSColin Finck     CloseHandle(pi.hThread);
3028c2c66affSColin Finck 
3029c2c66affSColin Finck     /* unset breakaway ok */
3030c2c66affSColin Finck     limit_info.BasicLimitInformation.LimitFlags = 0;
3031c2c66affSColin Finck     ret = pSetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info));
3032c2c66affSColin Finck     ok(ret, "SetInformationJobObject error %u\n", GetLastError());
3033c2c66affSColin Finck }
3034c2c66affSColin Finck 
test_StartupNoConsole(void)3035c2c66affSColin Finck static void test_StartupNoConsole(void)
3036c2c66affSColin Finck {
3037c2c66affSColin Finck #ifndef _WIN64
3038c2c66affSColin Finck     char                buffer[MAX_PATH];
3039c2c66affSColin Finck     STARTUPINFOA        startup;
3040c2c66affSColin Finck     PROCESS_INFORMATION info;
3041c2c66affSColin Finck 
3042c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
3043c2c66affSColin Finck     startup.cb = sizeof(startup);
3044c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
3045c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
3046c2c66affSColin Finck     get_file_name(resfile);
3047c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3048c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3049c2c66affSColin Finck                       &info), "CreateProcess\n");
3050c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3051c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3052c2c66affSColin Finck     okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3053c2c66affSColin Finck     okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3054c2c66affSColin Finck     okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3055c2c66affSColin Finck     okChildInt("TEB", "hStdInput", 0);
3056c2c66affSColin Finck     okChildInt("TEB", "hStdOutput", 0);
3057c2c66affSColin Finck     okChildInt("TEB", "hStdError", 0);
3058c2c66affSColin Finck     release_memory();
3059c2c66affSColin Finck     DeleteFileA(resfile);
3060c2c66affSColin Finck #endif
3061c2c66affSColin Finck }
3062c2c66affSColin Finck 
test_DetachConsoleHandles(void)3063c2c66affSColin Finck static void test_DetachConsoleHandles(void)
3064c2c66affSColin Finck {
3065c2c66affSColin Finck #ifndef _WIN64
3066c2c66affSColin Finck     char                buffer[MAX_PATH];
3067c2c66affSColin Finck     STARTUPINFOA        startup;
3068c2c66affSColin Finck     PROCESS_INFORMATION info;
3069c2c66affSColin Finck     UINT                result;
3070c2c66affSColin Finck 
3071c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
3072c2c66affSColin Finck     startup.cb = sizeof(startup);
3073c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
3074c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
3075c2c66affSColin Finck     startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
3076c2c66affSColin Finck     startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
3077c2c66affSColin Finck     startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
3078c2c66affSColin Finck     get_file_name(resfile);
3079c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3080c2c66affSColin Finck     ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3081c2c66affSColin Finck                       &info), "CreateProcess\n");
3082c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3083c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3084c2c66affSColin Finck 
3085c2c66affSColin Finck     result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile);
3086c2c66affSColin Finck     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3087c2c66affSColin Finck     result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile);
3088c2c66affSColin Finck     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3089c2c66affSColin Finck     result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile);
3090c2c66affSColin Finck     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3091c2c66affSColin Finck     result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile);
3092c2c66affSColin Finck     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3093c2c66affSColin Finck     result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile);
3094c2c66affSColin Finck     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3095c2c66affSColin Finck     result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile);
3096c2c66affSColin Finck     ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
3097c2c66affSColin Finck 
3098c2c66affSColin Finck     release_memory();
3099c2c66affSColin Finck     DeleteFileA(resfile);
3100c2c66affSColin Finck #endif
3101c2c66affSColin Finck }
3102c2c66affSColin Finck 
3103ed41a4deSAmine Khaldi #if defined(__i386__) || defined(__x86_64__)
read_nt_header(HANDLE process_handle,MEMORY_BASIC_INFORMATION * mbi,IMAGE_NT_HEADERS * nt_header)3104ed41a4deSAmine Khaldi static BOOL read_nt_header(HANDLE process_handle, MEMORY_BASIC_INFORMATION *mbi,
3105ed41a4deSAmine Khaldi                            IMAGE_NT_HEADERS *nt_header)
3106ed41a4deSAmine Khaldi {
3107ed41a4deSAmine Khaldi     IMAGE_DOS_HEADER dos_header;
3108ed41a4deSAmine Khaldi 
3109ed41a4deSAmine Khaldi     if (!ReadProcessMemory(process_handle, mbi->BaseAddress, &dos_header, sizeof(dos_header), NULL))
3110ed41a4deSAmine Khaldi         return FALSE;
3111ed41a4deSAmine Khaldi 
3112ed41a4deSAmine Khaldi     if ((dos_header.e_magic != IMAGE_DOS_SIGNATURE) ||
3113ed41a4deSAmine Khaldi         ((ULONG)dos_header.e_lfanew > mbi->RegionSize) ||
3114ed41a4deSAmine Khaldi         (dos_header.e_lfanew < sizeof(dos_header)))
3115ed41a4deSAmine Khaldi         return FALSE;
3116ed41a4deSAmine Khaldi 
3117ed41a4deSAmine Khaldi     if (!ReadProcessMemory(process_handle, (char *)mbi->BaseAddress + dos_header.e_lfanew,
3118ed41a4deSAmine Khaldi                            nt_header, sizeof(*nt_header), NULL))
3119ed41a4deSAmine Khaldi         return FALSE;
3120ed41a4deSAmine Khaldi 
3121ed41a4deSAmine Khaldi     return (nt_header->Signature == IMAGE_NT_SIGNATURE);
3122ed41a4deSAmine Khaldi }
3123ed41a4deSAmine Khaldi 
get_process_exe(HANDLE process_handle,IMAGE_NT_HEADERS * nt_header)3124ed41a4deSAmine Khaldi static PVOID get_process_exe(HANDLE process_handle, IMAGE_NT_HEADERS *nt_header)
3125ed41a4deSAmine Khaldi {
3126ed41a4deSAmine Khaldi     PVOID exe_base, address;
3127ed41a4deSAmine Khaldi     MEMORY_BASIC_INFORMATION mbi;
3128ed41a4deSAmine Khaldi 
3129ed41a4deSAmine Khaldi     /* Find the EXE base in the new process */
3130ed41a4deSAmine Khaldi     exe_base = NULL;
3131ed41a4deSAmine Khaldi     for (address = NULL ;
3132ed41a4deSAmine Khaldi          VirtualQueryEx(process_handle, address, &mbi, sizeof(mbi)) ;
3133ed41a4deSAmine Khaldi          address = (char *)mbi.BaseAddress + mbi.RegionSize) {
3134ed41a4deSAmine Khaldi         if ((mbi.Type == SEC_IMAGE) &&
3135ed41a4deSAmine Khaldi             read_nt_header(process_handle, &mbi, nt_header) &&
3136ed41a4deSAmine Khaldi             !(nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
3137ed41a4deSAmine Khaldi             exe_base = mbi.BaseAddress;
3138ed41a4deSAmine Khaldi             break;
3139ed41a4deSAmine Khaldi         }
3140ed41a4deSAmine Khaldi     }
3141ed41a4deSAmine Khaldi 
3142ed41a4deSAmine Khaldi     return exe_base;
3143ed41a4deSAmine Khaldi }
3144ed41a4deSAmine Khaldi 
are_imports_resolved(HANDLE process_handle,PVOID module_base,IMAGE_NT_HEADERS * nt_header)3145ed41a4deSAmine Khaldi static BOOL are_imports_resolved(HANDLE process_handle, PVOID module_base, IMAGE_NT_HEADERS *nt_header)
3146ed41a4deSAmine Khaldi {
3147ed41a4deSAmine Khaldi     BOOL ret;
3148ed41a4deSAmine Khaldi     IMAGE_IMPORT_DESCRIPTOR iid;
3149ed41a4deSAmine Khaldi     ULONG_PTR orig_iat_entry_value, iat_entry_value;
3150ed41a4deSAmine Khaldi 
3151ed41a4deSAmine Khaldi     ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, "Import table VA is zero\n");
3152ed41a4deSAmine Khaldi     ok(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, "Import table Size is zero\n");
3153ed41a4deSAmine Khaldi 
3154ed41a4deSAmine Khaldi     if (!nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ||
3155ed41a4deSAmine Khaldi         !nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
3156ed41a4deSAmine Khaldi         return FALSE;
3157ed41a4deSAmine Khaldi 
3158ed41a4deSAmine Khaldi     /* Read the first IID */
3159ed41a4deSAmine Khaldi     ret = ReadProcessMemory(process_handle,
3160ed41a4deSAmine Khaldi                             (char *)module_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
3161ed41a4deSAmine Khaldi                             &iid, sizeof(iid), NULL);
3162ed41a4deSAmine Khaldi     ok(ret, "Failed to read remote module IID (%d)\n", GetLastError());
3163ed41a4deSAmine Khaldi 
3164ed41a4deSAmine Khaldi     /* Validate the IID is present and not a bound import, and that we have
3165ed41a4deSAmine Khaldi        an OriginalFirstThunk to compare with */
3166ed41a4deSAmine Khaldi     ok(iid.Name, "Module first IID does not have a Name\n");
3167ed41a4deSAmine Khaldi     ok(iid.FirstThunk, "Module first IID does not have a FirstThunk\n");
3168ed41a4deSAmine Khaldi     ok(!iid.TimeDateStamp, "Module first IID is a bound import (UNSUPPORTED for current test)\n");
3169ed41a4deSAmine Khaldi     ok(iid.OriginalFirstThunk, "Module first IID does not have an OriginalFirstThunk (UNSUPPORTED for current test)\n");
3170ed41a4deSAmine Khaldi 
3171ed41a4deSAmine Khaldi     /* Read a single IAT entry from the FirstThunk */
3172ed41a4deSAmine Khaldi     ret = ReadProcessMemory(process_handle, (char *)module_base + iid.FirstThunk,
3173ed41a4deSAmine Khaldi                             &iat_entry_value, sizeof(iat_entry_value), NULL);
3174ed41a4deSAmine Khaldi     ok(ret, "Failed to read IAT entry from FirstThunk (%d)\n", GetLastError());
3175ed41a4deSAmine Khaldi     ok(iat_entry_value, "IAT entry in FirstThunk is NULL\n");
3176ed41a4deSAmine Khaldi 
3177ed41a4deSAmine Khaldi     /* Read a single IAT entry from the OriginalFirstThunk */
3178ed41a4deSAmine Khaldi     ret = ReadProcessMemory(process_handle, (char *)module_base + iid.OriginalFirstThunk,
3179ed41a4deSAmine Khaldi                             &orig_iat_entry_value, sizeof(orig_iat_entry_value), NULL);
3180ed41a4deSAmine Khaldi     ok(ret, "Failed to read IAT entry from OriginalFirstThunk (%d)\n", GetLastError());
3181ed41a4deSAmine Khaldi     ok(orig_iat_entry_value, "IAT entry in OriginalFirstThunk is NULL\n");
3182ed41a4deSAmine Khaldi 
3183ed41a4deSAmine Khaldi     return iat_entry_value != orig_iat_entry_value;
3184ed41a4deSAmine Khaldi }
3185ed41a4deSAmine Khaldi 
test_SuspendProcessNewThread(void)3186ed41a4deSAmine Khaldi static void test_SuspendProcessNewThread(void)
3187ed41a4deSAmine Khaldi {
3188ed41a4deSAmine Khaldi     BOOL ret;
3189ed41a4deSAmine Khaldi     STARTUPINFOA si = {0};
3190ed41a4deSAmine Khaldi     PROCESS_INFORMATION pi = {0};
3191ed41a4deSAmine Khaldi     PVOID exe_base, exit_thread_ptr;
3192ed41a4deSAmine Khaldi     IMAGE_NT_HEADERS nt_header;
3193ed41a4deSAmine Khaldi     HANDLE thread_handle = NULL;
3194ed41a4deSAmine Khaldi     DWORD dret, exit_code = 0;
3195ed41a4deSAmine Khaldi     CONTEXT ctx;
3196ed41a4deSAmine Khaldi 
3197ed41a4deSAmine Khaldi     exit_thread_ptr = GetProcAddress(hkernel32, "ExitThread");
3198ed41a4deSAmine Khaldi     ok(exit_thread_ptr != NULL, "GetProcAddress ExitThread failed\n");
3199ed41a4deSAmine Khaldi 
3200ed41a4deSAmine Khaldi     si.cb = sizeof(si);
3201ed41a4deSAmine Khaldi     ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3202ed41a4deSAmine Khaldi     ok(ret, "Failed to create process (%d)\n", GetLastError());
3203ed41a4deSAmine Khaldi 
3204ed41a4deSAmine Khaldi     exe_base = get_process_exe(pi.hProcess, &nt_header);
3205ed41a4deSAmine Khaldi     ok(exe_base != NULL, "Could not find EXE in remote process\n");
3206ed41a4deSAmine Khaldi 
3207ed41a4deSAmine Khaldi     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3208ed41a4deSAmine Khaldi     ok(!ret, "IAT entry resolved prematurely\n");
3209ed41a4deSAmine Khaldi 
3210ed41a4deSAmine Khaldi     thread_handle = CreateRemoteThread(pi.hProcess, NULL, 0,
3211ed41a4deSAmine Khaldi                                        (LPTHREAD_START_ROUTINE)exit_thread_ptr,
3212ed41a4deSAmine Khaldi                                        (PVOID)(ULONG_PTR)0x1234, CREATE_SUSPENDED, NULL);
3213ed41a4deSAmine Khaldi     ok(thread_handle != NULL, "Could not create remote thread (%d)\n", GetLastError());
3214ed41a4deSAmine Khaldi 
3215ed41a4deSAmine Khaldi     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3216ed41a4deSAmine Khaldi     ok(!ret, "IAT entry resolved prematurely\n");
3217ed41a4deSAmine Khaldi 
3218ed41a4deSAmine Khaldi     ctx.ContextFlags = CONTEXT_ALL;
3219ed41a4deSAmine Khaldi     ret = GetThreadContext( thread_handle, &ctx );
3220ed41a4deSAmine Khaldi     ok( ret, "Failed retrieving remote thread context (%d)\n", GetLastError() );
3221ed41a4deSAmine Khaldi     ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags );
3222ed41a4deSAmine Khaldi #ifdef __x86_64__
3223ed41a4deSAmine Khaldi     ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax );
3224ed41a4deSAmine Khaldi     ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx );
3225ed41a4deSAmine Khaldi     ok( ctx.Rcx == (ULONG_PTR)exit_thread_ptr, "wrong rcx %lx/%p\n", ctx.Rcx, exit_thread_ptr );
3226ed41a4deSAmine Khaldi     ok( ctx.Rdx == 0x1234, "wrong rdx %lx\n", ctx.Rdx );
3227ed41a4deSAmine Khaldi     ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi );
3228ed41a4deSAmine Khaldi     ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi );
3229ed41a4deSAmine Khaldi     ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp );
3230ed41a4deSAmine Khaldi     ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 );
3231ed41a4deSAmine Khaldi     ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 );
3232ed41a4deSAmine Khaldi     ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 );
3233ed41a4deSAmine Khaldi     ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 );
3234ed41a4deSAmine Khaldi     ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 );
3235ed41a4deSAmine Khaldi     ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 );
3236ed41a4deSAmine Khaldi     ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 );
3237ed41a4deSAmine Khaldi     ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 );
3238ed41a4deSAmine Khaldi     ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp );
3239ed41a4deSAmine Khaldi     ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags );
3240ed41a4deSAmine Khaldi     ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr );
3241ed41a4deSAmine Khaldi     ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3242ed41a4deSAmine Khaldi #else
3243ed41a4deSAmine Khaldi     ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp );
3244ed41a4deSAmine Khaldi     if (!ctx.Ebp)  /* winxp is completely different */
3245ed41a4deSAmine Khaldi     {
3246ed41a4deSAmine Khaldi         ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx );
3247ed41a4deSAmine Khaldi         ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx );
3248ed41a4deSAmine Khaldi         ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi );
3249ed41a4deSAmine Khaldi         ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi );
3250ed41a4deSAmine Khaldi     }
3251ed41a4deSAmine Khaldi     ok( ctx.Eax == (ULONG_PTR)exit_thread_ptr, "wrong eax %08x/%p\n", ctx.Eax, exit_thread_ptr );
3252ed41a4deSAmine Khaldi     ok( ctx.Ebx == 0x1234, "wrong ebx %08x\n", ctx.Ebx );
3253ed41a4deSAmine Khaldi     ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3254ed41a4deSAmine Khaldi         "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp );
3255ed41a4deSAmine Khaldi     ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags );
3256ed41a4deSAmine Khaldi     ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord );
3257ed41a4deSAmine Khaldi     ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3258ed41a4deSAmine Khaldi #endif
3259ed41a4deSAmine Khaldi 
3260ed41a4deSAmine Khaldi     ResumeThread( thread_handle );
3261ed41a4deSAmine Khaldi     dret = WaitForSingleObject(thread_handle, 60000);
3262ed41a4deSAmine Khaldi     ok(dret == WAIT_OBJECT_0, "Waiting for remote thread failed (%d)\n", GetLastError());
3263ed41a4deSAmine Khaldi     ret = GetExitCodeThread(thread_handle, &exit_code);
3264ed41a4deSAmine Khaldi     ok(ret, "Failed to retrieve remote thread exit code (%d)\n", GetLastError());
3265ed41a4deSAmine Khaldi     ok(exit_code == 0x1234, "Invalid remote thread exit code\n");
3266ed41a4deSAmine Khaldi 
3267ed41a4deSAmine Khaldi     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3268ed41a4deSAmine Khaldi     ok(ret, "EXE IAT entry not resolved\n");
3269ed41a4deSAmine Khaldi 
3270ed41a4deSAmine Khaldi     if (thread_handle)
3271ed41a4deSAmine Khaldi         CloseHandle(thread_handle);
3272ed41a4deSAmine Khaldi 
3273ed41a4deSAmine Khaldi     TerminateProcess(pi.hProcess, 0);
3274ed41a4deSAmine Khaldi     WaitForSingleObject(pi.hProcess, 10000);
3275ed41a4deSAmine Khaldi     CloseHandle(pi.hProcess);
3276ed41a4deSAmine Khaldi     CloseHandle(pi.hThread);
3277ed41a4deSAmine Khaldi }
3278ed41a4deSAmine Khaldi 
test_SuspendProcessState(void)3279ed41a4deSAmine Khaldi static void test_SuspendProcessState(void)
3280ed41a4deSAmine Khaldi {
3281ed41a4deSAmine Khaldi     struct pipe_params
3282ed41a4deSAmine Khaldi     {
3283ed41a4deSAmine Khaldi         ULONG pipe_write_buf;
3284ed41a4deSAmine Khaldi         ULONG pipe_read_buf;
3285ed41a4deSAmine Khaldi         ULONG bytes_returned;
3286ed41a4deSAmine Khaldi         CHAR pipe_name[MAX_PATH];
3287ed41a4deSAmine Khaldi     };
3288ed41a4deSAmine Khaldi 
3289ed41a4deSAmine Khaldi #ifdef __x86_64__
3290ed41a4deSAmine Khaldi     struct remote_rop_chain
3291ed41a4deSAmine Khaldi     {
3292ed41a4deSAmine Khaldi         void     *exit_process_ptr;
3293ed41a4deSAmine Khaldi         ULONG_PTR home_rcx;
3294ed41a4deSAmine Khaldi         ULONG_PTR home_rdx;
3295ed41a4deSAmine Khaldi         ULONG_PTR home_r8;
3296ed41a4deSAmine Khaldi         ULONG_PTR home_r9;
3297ed41a4deSAmine Khaldi         ULONG_PTR pipe_read_buf_size;
3298ed41a4deSAmine Khaldi         ULONG_PTR bytes_returned;
3299ed41a4deSAmine Khaldi         ULONG_PTR timeout;
3300ed41a4deSAmine Khaldi     };
3301ed41a4deSAmine Khaldi #else
3302ed41a4deSAmine Khaldi     struct remote_rop_chain
3303ed41a4deSAmine Khaldi     {
3304ed41a4deSAmine Khaldi         void     *exit_process_ptr;
3305ed41a4deSAmine Khaldi         ULONG_PTR pipe_name;
3306ed41a4deSAmine Khaldi         ULONG_PTR pipe_write_buf;
3307ed41a4deSAmine Khaldi         ULONG_PTR pipe_write_buf_size;
3308ed41a4deSAmine Khaldi         ULONG_PTR pipe_read_buf;
3309ed41a4deSAmine Khaldi         ULONG_PTR pipe_read_buf_size;
3310ed41a4deSAmine Khaldi         ULONG_PTR bytes_returned;
3311ed41a4deSAmine Khaldi         ULONG_PTR timeout;
3312ed41a4deSAmine Khaldi         void     *unreached_ret;
3313ed41a4deSAmine Khaldi         ULONG_PTR exit_code;
3314ed41a4deSAmine Khaldi     };
3315ed41a4deSAmine Khaldi #endif
3316ed41a4deSAmine Khaldi 
3317ed41a4deSAmine Khaldi     static const char pipe_name[] = "\\\\.\\pipe\\TestPipe";
3318ed41a4deSAmine Khaldi     static const ULONG pipe_write_magic = 0x454e4957;
3319ed41a4deSAmine Khaldi     STARTUPINFOA si = {0};
3320ed41a4deSAmine Khaldi     PROCESS_INFORMATION pi = {0};
3321ed41a4deSAmine Khaldi     PVOID exe_base, remote_pipe_params, exit_process_ptr,
3322ed41a4deSAmine Khaldi           call_named_pipe_a;
3323ed41a4deSAmine Khaldi     IMAGE_NT_HEADERS nt_header;
3324ed41a4deSAmine Khaldi     struct pipe_params pipe_params;
3325ed41a4deSAmine Khaldi     struct remote_rop_chain rop_chain;
3326ed41a4deSAmine Khaldi     CONTEXT ctx;
3327ed41a4deSAmine Khaldi     HANDLE server_pipe_handle;
3328ed41a4deSAmine Khaldi     BOOL pipe_connected;
3329ed41a4deSAmine Khaldi     ULONG pipe_magic, numb;
3330ed41a4deSAmine Khaldi     BOOL ret;
3331ed41a4deSAmine Khaldi     void *entry_ptr, *peb_ptr;
3332ed41a4deSAmine Khaldi     PEB child_peb;
3333ed41a4deSAmine Khaldi 
3334ed41a4deSAmine Khaldi     exit_process_ptr = GetProcAddress(hkernel32, "ExitProcess");
3335ed41a4deSAmine Khaldi     ok(exit_process_ptr != NULL, "GetProcAddress ExitProcess failed\n");
3336ed41a4deSAmine Khaldi 
3337ed41a4deSAmine Khaldi     call_named_pipe_a = GetProcAddress(hkernel32, "CallNamedPipeA");
3338ed41a4deSAmine Khaldi     ok(call_named_pipe_a != NULL, "GetProcAddress CallNamedPipeA failed\n");
3339ed41a4deSAmine Khaldi 
3340ed41a4deSAmine Khaldi     si.cb = sizeof(si);
3341ed41a4deSAmine Khaldi     ret = CreateProcessA(NULL, selfname, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
3342ed41a4deSAmine Khaldi     ok(ret, "Failed to create process (%d)\n", GetLastError());
3343ed41a4deSAmine Khaldi 
3344ed41a4deSAmine Khaldi     exe_base = get_process_exe(pi.hProcess, &nt_header);
3345ed41a4deSAmine Khaldi     /* Make sure we found the EXE in the new process */
3346ed41a4deSAmine Khaldi     ok(exe_base != NULL, "Could not find EXE in remote process\n");
3347ed41a4deSAmine Khaldi 
3348ed41a4deSAmine Khaldi     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3349ed41a4deSAmine Khaldi     ok(!ret, "IAT entry resolved prematurely\n");
3350ed41a4deSAmine Khaldi 
3351ed41a4deSAmine Khaldi     server_pipe_handle = CreateNamedPipeA(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH,
3352ed41a4deSAmine Khaldi                                         PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0x20000, 0x20000,
3353ed41a4deSAmine Khaldi                                         0, NULL);
3354ed41a4deSAmine Khaldi     ok(server_pipe_handle != INVALID_HANDLE_VALUE, "Failed to create communication pipe (%d)\n", GetLastError());
3355ed41a4deSAmine Khaldi 
3356ed41a4deSAmine Khaldi     /* Set up the remote process environment */
3357ed41a4deSAmine Khaldi     ctx.ContextFlags = CONTEXT_ALL;
3358ed41a4deSAmine Khaldi     ret = GetThreadContext(pi.hThread, &ctx);
3359ed41a4deSAmine Khaldi     ok(ret, "Failed retrieving remote thread context (%d)\n", GetLastError());
3360ed41a4deSAmine Khaldi     ok( ctx.ContextFlags == CONTEXT_ALL, "wrong flags %x\n", ctx.ContextFlags );
3361ed41a4deSAmine Khaldi 
3362ed41a4deSAmine Khaldi     remote_pipe_params = VirtualAllocEx(pi.hProcess, NULL, sizeof(pipe_params), MEM_COMMIT, PAGE_READWRITE);
3363ed41a4deSAmine Khaldi     ok(remote_pipe_params != NULL, "Failed allocating memory in remote process (%d)\n", GetLastError());
3364ed41a4deSAmine Khaldi 
3365ed41a4deSAmine Khaldi     pipe_params.pipe_write_buf = pipe_write_magic;
3366ed41a4deSAmine Khaldi     pipe_params.pipe_read_buf = 0;
3367ed41a4deSAmine Khaldi     pipe_params.bytes_returned = 0;
3368ed41a4deSAmine Khaldi     strcpy(pipe_params.pipe_name, pipe_name);
3369ed41a4deSAmine Khaldi 
3370ed41a4deSAmine Khaldi     ret = WriteProcessMemory(pi.hProcess, remote_pipe_params,
3371ed41a4deSAmine Khaldi                              &pipe_params, sizeof(pipe_params), NULL);
3372ed41a4deSAmine Khaldi     ok(ret, "Failed to write to remote process memory (%d)\n", GetLastError());
3373ed41a4deSAmine Khaldi 
3374ed41a4deSAmine Khaldi #ifdef __x86_64__
3375ed41a4deSAmine Khaldi     ok( !ctx.Rax, "rax is not zero %lx\n", ctx.Rax );
3376ed41a4deSAmine Khaldi     ok( !ctx.Rbx, "rbx is not zero %lx\n", ctx.Rbx );
3377ed41a4deSAmine Khaldi     ok( !ctx.Rsi, "rsi is not zero %lx\n", ctx.Rsi );
3378ed41a4deSAmine Khaldi     ok( !ctx.Rdi, "rdi is not zero %lx\n", ctx.Rdi );
3379ed41a4deSAmine Khaldi     ok( !ctx.Rbp, "rbp is not zero %lx\n", ctx.Rbp );
3380ed41a4deSAmine Khaldi     ok( !ctx.R8, "r8 is not zero %lx\n", ctx.R8 );
3381ed41a4deSAmine Khaldi     ok( !ctx.R9, "r9 is not zero %lx\n", ctx.R9 );
3382ed41a4deSAmine Khaldi     ok( !ctx.R10, "r10 is not zero %lx\n", ctx.R10 );
3383ed41a4deSAmine Khaldi     ok( !ctx.R11, "r11 is not zero %lx\n", ctx.R11 );
3384ed41a4deSAmine Khaldi     ok( !ctx.R12, "r12 is not zero %lx\n", ctx.R12 );
3385ed41a4deSAmine Khaldi     ok( !ctx.R13, "r13 is not zero %lx\n", ctx.R13 );
3386ed41a4deSAmine Khaldi     ok( !ctx.R14, "r14 is not zero %lx\n", ctx.R14 );
3387ed41a4deSAmine Khaldi     ok( !ctx.R15, "r15 is not zero %lx\n", ctx.R15 );
3388ed41a4deSAmine Khaldi     ok( !((ctx.Rsp + 0x28) & 0xfff), "rsp is not at top of stack page %lx\n", ctx.Rsp );
3389ed41a4deSAmine Khaldi     ok( ctx.EFlags == 0x200, "wrong flags %08x\n", ctx.EFlags );
3390ed41a4deSAmine Khaldi     ok( ctx.MxCsr == 0x1f80, "wrong mxcsr %08x\n", ctx.MxCsr );
3391ed41a4deSAmine Khaldi     ok( ctx.FltSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FltSave.ControlWord );
3392ed41a4deSAmine Khaldi     entry_ptr = (void *)ctx.Rcx;
3393ed41a4deSAmine Khaldi     peb_ptr = (void *)ctx.Rdx;
3394ed41a4deSAmine Khaldi 
3395ed41a4deSAmine Khaldi     rop_chain.exit_process_ptr = exit_process_ptr;
3396ed41a4deSAmine Khaldi     ctx.Rcx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3397ed41a4deSAmine Khaldi     ctx.Rdx = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3398ed41a4deSAmine Khaldi     ctx.R8 = sizeof(pipe_params.pipe_write_buf);
3399ed41a4deSAmine Khaldi     ctx.R9 = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3400ed41a4deSAmine Khaldi     rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3401ed41a4deSAmine Khaldi     rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3402ed41a4deSAmine Khaldi     rop_chain.timeout = 10000;
3403ed41a4deSAmine Khaldi 
3404ed41a4deSAmine Khaldi     ctx.Rip = (ULONG_PTR)call_named_pipe_a;
3405ed41a4deSAmine Khaldi     ctx.Rsp -= sizeof(rop_chain);
3406ed41a4deSAmine Khaldi     ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Rsp, &rop_chain, sizeof(rop_chain), NULL);
3407ed41a4deSAmine Khaldi     ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3408ed41a4deSAmine Khaldi #else
3409ed41a4deSAmine Khaldi     ok( !ctx.Ebp || broken(ctx.Ebp), /* winxp */ "ebp is not zero %08x\n", ctx.Ebp );
3410ed41a4deSAmine Khaldi     if (!ctx.Ebp)  /* winxp is completely different */
3411ed41a4deSAmine Khaldi     {
3412ed41a4deSAmine Khaldi         ok( !ctx.Ecx, "ecx is not zero %08x\n", ctx.Ecx );
3413ed41a4deSAmine Khaldi         ok( !ctx.Edx, "edx is not zero %08x\n", ctx.Edx );
3414ed41a4deSAmine Khaldi         ok( !ctx.Esi, "esi is not zero %08x\n", ctx.Esi );
3415ed41a4deSAmine Khaldi         ok( !ctx.Edi, "edi is not zero %08x\n", ctx.Edi );
3416ed41a4deSAmine Khaldi     }
3417ed41a4deSAmine Khaldi     ok( !((ctx.Esp + 0x10) & 0xfff) || broken( !((ctx.Esp + 4) & 0xfff) ), /* winxp, w2k3 */
3418ed41a4deSAmine Khaldi         "esp is not at top of stack page or properly aligned: %08x\n", ctx.Esp );
3419ed41a4deSAmine Khaldi     ok( (ctx.EFlags & ~2) == 0x200, "wrong flags %08x\n", ctx.EFlags );
3420ed41a4deSAmine Khaldi     ok( (WORD)ctx.FloatSave.ControlWord == 0x27f, "wrong control %08x\n", ctx.FloatSave.ControlWord );
3421ed41a4deSAmine Khaldi     ok( *(WORD *)ctx.ExtendedRegisters == 0x27f, "wrong control %08x\n", *(WORD *)ctx.ExtendedRegisters );
3422ed41a4deSAmine Khaldi     entry_ptr = (void *)ctx.Eax;
3423ed41a4deSAmine Khaldi     peb_ptr = (void *)ctx.Ebx;
3424ed41a4deSAmine Khaldi 
3425ed41a4deSAmine Khaldi     rop_chain.exit_process_ptr = exit_process_ptr;
3426ed41a4deSAmine Khaldi     rop_chain.pipe_name = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_name);
3427ed41a4deSAmine Khaldi     rop_chain.pipe_write_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_write_buf);
3428ed41a4deSAmine Khaldi     rop_chain.pipe_write_buf_size = sizeof(pipe_params.pipe_write_buf);
3429ed41a4deSAmine Khaldi     rop_chain.pipe_read_buf = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, pipe_read_buf);
3430ed41a4deSAmine Khaldi     rop_chain.pipe_read_buf_size = sizeof(pipe_params.pipe_read_buf);
3431ed41a4deSAmine Khaldi     rop_chain.bytes_returned = (ULONG_PTR)remote_pipe_params + offsetof(struct pipe_params, bytes_returned);
3432ed41a4deSAmine Khaldi     rop_chain.timeout = 10000;
3433ed41a4deSAmine Khaldi     rop_chain.exit_code = 0;
3434ed41a4deSAmine Khaldi 
3435ed41a4deSAmine Khaldi     ctx.Eip = (ULONG_PTR)call_named_pipe_a;
3436ed41a4deSAmine Khaldi     ctx.Esp -= sizeof(rop_chain);
3437ed41a4deSAmine Khaldi     ret = WriteProcessMemory(pi.hProcess, (void *)ctx.Esp, &rop_chain, sizeof(rop_chain), NULL);
3438ed41a4deSAmine Khaldi     ok(ret, "Failed to write to remote process thread stack (%d)\n", GetLastError());
3439ed41a4deSAmine Khaldi #endif
3440ed41a4deSAmine Khaldi 
3441ed41a4deSAmine Khaldi     ret = ReadProcessMemory( pi.hProcess, peb_ptr, &child_peb, sizeof(child_peb), NULL );
3442ed41a4deSAmine Khaldi     ok( ret, "Failed to read PEB (%u)\n", GetLastError() );
3443ed41a4deSAmine Khaldi     ok( child_peb.ImageBaseAddress == exe_base, "wrong base %p/%p\n",
3444ed41a4deSAmine Khaldi         child_peb.ImageBaseAddress, exe_base );
3445ed41a4deSAmine Khaldi     ok( entry_ptr == (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint,
3446ed41a4deSAmine Khaldi         "wrong entry point %p/%p\n", entry_ptr,
3447ed41a4deSAmine Khaldi         (char *)exe_base + nt_header.OptionalHeader.AddressOfEntryPoint );
3448ed41a4deSAmine Khaldi 
3449ed41a4deSAmine Khaldi     ret = SetThreadContext(pi.hThread, &ctx);
3450ed41a4deSAmine Khaldi     ok(ret, "Failed to set remote thread context (%d)\n", GetLastError());
3451ed41a4deSAmine Khaldi 
3452ed41a4deSAmine Khaldi     ResumeThread(pi.hThread);
3453ed41a4deSAmine Khaldi 
3454ed41a4deSAmine Khaldi     pipe_connected = ConnectNamedPipe(server_pipe_handle, NULL) || (GetLastError() == ERROR_PIPE_CONNECTED);
3455ed41a4deSAmine Khaldi     ok(pipe_connected, "Pipe did not connect\n");
3456ed41a4deSAmine Khaldi 
3457ed41a4deSAmine Khaldi     ret = ReadFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3458ed41a4deSAmine Khaldi     ok(ret, "Failed to read buffer from pipe (%d)\n", GetLastError());
3459ed41a4deSAmine Khaldi 
3460ed41a4deSAmine Khaldi     ok(pipe_magic == pipe_write_magic, "Did not get the correct magic from the remote process\n");
3461ed41a4deSAmine Khaldi 
3462ed41a4deSAmine Khaldi     /* Validate the Imports, at this point the thread in the new process should have
3463ed41a4deSAmine Khaldi        initialized the EXE module imports and call each dll DllMain notifying it on
3464ed41a4deSAmine Khaldi        the new thread in the process. */
3465ed41a4deSAmine Khaldi     ret = are_imports_resolved(pi.hProcess, exe_base, &nt_header);
3466ed41a4deSAmine Khaldi     ok(ret, "EXE IAT is not resolved\n");
3467ed41a4deSAmine Khaldi 
3468ed41a4deSAmine Khaldi     ret = WriteFile(server_pipe_handle, &pipe_magic, sizeof(pipe_magic), &numb, NULL);
3469ed41a4deSAmine Khaldi     ok(ret, "Failed to write the magic back to the pipe (%d)\n", GetLastError());
3470ed41a4deSAmine Khaldi 
3471ed41a4deSAmine Khaldi     CloseHandle(server_pipe_handle);
3472ed41a4deSAmine Khaldi     TerminateProcess(pi.hProcess, 0);
3473ed41a4deSAmine Khaldi     WaitForSingleObject(pi.hProcess, 10000);
3474ed41a4deSAmine Khaldi     CloseHandle(pi.hProcess);
3475ed41a4deSAmine Khaldi     CloseHandle(pi.hThread);
3476ed41a4deSAmine Khaldi }
3477ed41a4deSAmine Khaldi #else
test_SuspendProcessNewThread(void)3478ed41a4deSAmine Khaldi static void test_SuspendProcessNewThread(void)
3479ed41a4deSAmine Khaldi {
3480ed41a4deSAmine Khaldi }
test_SuspendProcessState(void)3481ed41a4deSAmine Khaldi static void test_SuspendProcessState(void)
3482ed41a4deSAmine Khaldi {
3483ed41a4deSAmine Khaldi }
3484ed41a4deSAmine Khaldi #endif
3485ed41a4deSAmine Khaldi 
test_DetachStdHandles(void)3486c2c66affSColin Finck static void test_DetachStdHandles(void)
3487c2c66affSColin Finck {
3488c2c66affSColin Finck #ifndef _WIN64
3489c2c66affSColin Finck     char                buffer[MAX_PATH], tempfile[MAX_PATH];
3490c2c66affSColin Finck     STARTUPINFOA        startup;
3491c2c66affSColin Finck     PROCESS_INFORMATION info;
3492c2c66affSColin Finck     HANDLE              hstdin, hstdout, hstderr, htemp;
3493c2c66affSColin Finck     BOOL                res;
3494c2c66affSColin Finck 
3495c2c66affSColin Finck     hstdin = GetStdHandle(STD_INPUT_HANDLE);
3496c2c66affSColin Finck     hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
3497c2c66affSColin Finck     hstderr = GetStdHandle(STD_ERROR_HANDLE);
3498c2c66affSColin Finck 
3499c2c66affSColin Finck     get_file_name(tempfile);
3500c2c66affSColin Finck     htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3501c2c66affSColin Finck     ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n");
3502c2c66affSColin Finck 
3503c2c66affSColin Finck     memset(&startup, 0, sizeof(startup));
3504c2c66affSColin Finck     startup.cb = sizeof(startup);
3505c2c66affSColin Finck     startup.dwFlags = STARTF_USESHOWWINDOW;
3506c2c66affSColin Finck     startup.wShowWindow = SW_SHOWNORMAL;
3507c2c66affSColin Finck     get_file_name(resfile);
3508c2c66affSColin Finck     sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
3509c2c66affSColin Finck 
3510c2c66affSColin Finck     SetStdHandle(STD_INPUT_HANDLE, htemp);
3511c2c66affSColin Finck     SetStdHandle(STD_OUTPUT_HANDLE, htemp);
3512c2c66affSColin Finck     SetStdHandle(STD_ERROR_HANDLE, htemp);
3513c2c66affSColin Finck 
3514c2c66affSColin Finck     res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
3515c2c66affSColin Finck                       &info);
3516c2c66affSColin Finck 
3517c2c66affSColin Finck     SetStdHandle(STD_INPUT_HANDLE, hstdin);
3518c2c66affSColin Finck     SetStdHandle(STD_OUTPUT_HANDLE, hstdout);
3519c2c66affSColin Finck     SetStdHandle(STD_ERROR_HANDLE, hstderr);
3520c2c66affSColin Finck 
3521c2c66affSColin Finck     ok(res, "CreateProcess failed\n");
3522c2c66affSColin Finck     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
3523c2c66affSColin Finck     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
3524c2c66affSColin Finck     okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
3525c2c66affSColin Finck     okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
3526c2c66affSColin Finck     okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
3527c2c66affSColin Finck     okChildInt("TEB", "hStdInput", 0);
3528c2c66affSColin Finck     okChildInt("TEB", "hStdOutput", 0);
3529c2c66affSColin Finck     okChildInt("TEB", "hStdError", 0);
3530c2c66affSColin Finck     release_memory();
3531c2c66affSColin Finck     DeleteFileA(resfile);
3532c2c66affSColin Finck 
3533c2c66affSColin Finck     CloseHandle(htemp);
3534c2c66affSColin Finck     DeleteFileA(tempfile);
3535c2c66affSColin Finck #endif
3536c2c66affSColin Finck }
3537c2c66affSColin Finck 
test_GetNumaProcessorNode(void)3538c2c66affSColin Finck static void test_GetNumaProcessorNode(void)
3539c2c66affSColin Finck {
3540c2c66affSColin Finck     SYSTEM_INFO si;
3541c2c66affSColin Finck     UCHAR node;
3542c2c66affSColin Finck     BOOL ret;
3543c2c66affSColin Finck     int i;
3544c2c66affSColin Finck 
3545c2c66affSColin Finck     if (!pGetNumaProcessorNode)
3546c2c66affSColin Finck     {
3547c2c66affSColin Finck         win_skip("GetNumaProcessorNode is missing\n");
3548c2c66affSColin Finck         return;
3549c2c66affSColin Finck     }
3550c2c66affSColin Finck 
3551c2c66affSColin Finck     GetSystemInfo(&si);
3552c2c66affSColin Finck     for (i = 0; i < 256; i++)
3553c2c66affSColin Finck     {
3554c2c66affSColin Finck         SetLastError(0xdeadbeef);
3555c2c66affSColin Finck         node = (i < si.dwNumberOfProcessors) ? 0xFF : 0xAA;
3556c2c66affSColin Finck         ret = pGetNumaProcessorNode(i, &node);
3557c2c66affSColin Finck         if (i < si.dwNumberOfProcessors)
3558c2c66affSColin Finck         {
3559c2c66affSColin Finck             ok(ret, "GetNumaProcessorNode returned FALSE for processor %d\n", i);
3560c2c66affSColin Finck             ok(node != 0xFF, "expected node != 0xFF, but got 0xFF\n");
3561c2c66affSColin Finck         }
3562c2c66affSColin Finck         else
3563c2c66affSColin Finck         {
3564c2c66affSColin Finck             ok(!ret, "GetNumaProcessorNode returned TRUE for processor %d\n", i);
3565c2c66affSColin Finck             ok(node == 0xFF || broken(node == 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node);
3566c2c66affSColin Finck             ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3567c2c66affSColin Finck         }
3568c2c66affSColin Finck     }
3569c2c66affSColin Finck }
3570c2c66affSColin Finck 
test_session_info(void)3571c2c66affSColin Finck static void test_session_info(void)
3572c2c66affSColin Finck {
3573c2c66affSColin Finck     DWORD session_id, active_session;
3574c2c66affSColin Finck     BOOL r;
3575c2c66affSColin Finck 
3576c2c66affSColin Finck     if (!pProcessIdToSessionId)
3577c2c66affSColin Finck     {
3578c2c66affSColin Finck         win_skip("ProcessIdToSessionId is missing\n");
3579c2c66affSColin Finck         return;
3580c2c66affSColin Finck     }
3581c2c66affSColin Finck 
3582c2c66affSColin Finck     r = pProcessIdToSessionId(GetCurrentProcessId(), &session_id);
3583c2c66affSColin Finck     ok(r, "ProcessIdToSessionId failed: %u\n", GetLastError());
3584c2c66affSColin Finck     trace("session_id = %x\n", session_id);
3585c2c66affSColin Finck 
3586c2c66affSColin Finck     active_session = pWTSGetActiveConsoleSessionId();
3587c2c66affSColin Finck     trace("active_session = %x\n", active_session);
3588c2c66affSColin Finck }
3589c2c66affSColin Finck 
test_process_info(void)3590c2c66affSColin Finck static void test_process_info(void)
3591c2c66affSColin Finck {
3592c2c66affSColin Finck     char buf[4096];
3593c2c66affSColin Finck     static const ULONG info_size[] =
3594c2c66affSColin Finck     {
3595c2c66affSColin Finck         sizeof(PROCESS_BASIC_INFORMATION) /* ProcessBasicInformation */,
3596c2c66affSColin Finck         sizeof(QUOTA_LIMITS) /* ProcessQuotaLimits */,
3597c2c66affSColin Finck         sizeof(IO_COUNTERS) /* ProcessIoCounters */,
3598c2c66affSColin Finck         sizeof(VM_COUNTERS) /* ProcessVmCounters */,
3599c2c66affSColin Finck         sizeof(KERNEL_USER_TIMES) /* ProcessTimes */,
3600c2c66affSColin Finck         sizeof(ULONG) /* ProcessBasePriority */,
3601c2c66affSColin Finck         sizeof(ULONG) /* ProcessRaisePriority */,
3602c2c66affSColin Finck         sizeof(HANDLE) /* ProcessDebugPort */,
3603c2c66affSColin Finck         sizeof(HANDLE) /* ProcessExceptionPort */,
3604c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
3605c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
3606c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
3607c2c66affSColin Finck         sizeof(ULONG) /* ProcessDefaultHardErrorMode */,
3608c2c66affSColin Finck         0 /* ProcessIoPortHandlers: kernel-mode only */,
3609c2c66affSColin Finck         0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
3610c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
3611c2c66affSColin Finck         sizeof(ULONG) /* ProcessUserModeIOPL */,
3612c2c66affSColin Finck         sizeof(BOOLEAN) /* ProcessEnableAlignmentFaultFixup */,
3613c2c66affSColin Finck         sizeof(PROCESS_PRIORITY_CLASS) /* ProcessPriorityClass */,
3614c2c66affSColin Finck         sizeof(ULONG) /* ProcessWx86Information */,
3615c2c66affSColin Finck         sizeof(ULONG) /* ProcessHandleCount */,
3616c2c66affSColin Finck         sizeof(ULONG_PTR) /* ProcessAffinityMask */,
3617c2c66affSColin Finck         sizeof(ULONG) /* ProcessPriorityBoost */,
3618c2c66affSColin Finck         0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
3619c2c66affSColin Finck         0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
3620c2c66affSColin Finck         0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
3621c2c66affSColin Finck         sizeof(ULONG_PTR) /* ProcessWow64Information */,
3622c2c66affSColin Finck         sizeof(buf) /* ProcessImageFileName */,
3623c2c66affSColin Finck         sizeof(ULONG) /* ProcessLUIDDeviceMapsEnabled */,
3624c2c66affSColin Finck         sizeof(ULONG) /* ProcessBreakOnTermination */,
3625c2c66affSColin Finck         sizeof(HANDLE) /* ProcessDebugObjectHandle */,
3626c2c66affSColin Finck         sizeof(ULONG) /* ProcessDebugFlags */,
3627c2c66affSColin Finck         sizeof(buf) /* ProcessHandleTracing */,
3628c2c66affSColin Finck         sizeof(ULONG) /* ProcessIoPriority */,
3629c2c66affSColin Finck         sizeof(ULONG) /* ProcessExecuteFlags */,
3630c2c66affSColin Finck         0 /* FIXME: sizeof(?) ProcessTlsInformation */,
3631c2c66affSColin Finck         0 /* FIXME: sizeof(?) ProcessCookie */,
3632c2c66affSColin Finck         sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */,
3633c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */,
3634c2c66affSColin Finck         sizeof(ULONG) /* ProcessPagePriority */,
3635c2c66affSColin Finck         40 /* ProcessInstrumentationCallback */,
3636c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
3637c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
3638c2c66affSColin Finck         sizeof(buf) /* ProcessImageFileNameWin32 */,
3639c2c66affSColin Finck         sizeof(HANDLE) /* ProcessImageFileMapping */,
3640c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_AFFINITY_UPDATE_MODE) ProcessAffinityUpdateMode */,
3641c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_MEMORY_ALLOCATION_MODE) ProcessMemoryAllocationMode */,
3642c2c66affSColin Finck         sizeof(USHORT) /* ProcessGroupInformation */,
3643c2c66affSColin Finck         sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */,
3644c2c66affSColin Finck         sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */,
3645c2c66affSColin Finck         0 /* FIXME: sizeof(PROCESS_WINDOW_INFORMATION) ProcessWindowInformation */,
3646c2c66affSColin Finck #if 0 /* FIXME: Add remaining classes */
3647c2c66affSColin Finck         sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */,
3648c2c66affSColin Finck         sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */,
3649c2c66affSColin Finck         sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */,
3650c2c66affSColin Finck         sizeof(?) /* ProcessHandleCheckingMode */,
3651c2c66affSColin Finck         sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION) /* ProcessKeepAliveCount */,
3652c2c66affSColin Finck         sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION) /* ProcessRevokeFileHandles */,
3653c2c66affSColin Finck         sizeof(PROCESS_WORKING_SET_CONTROL) /* ProcessWorkingSetControl */,
3654c2c66affSColin Finck         sizeof(?) /* ProcessHandleTable */,
3655c2c66affSColin Finck         sizeof(?) /* ProcessCheckStackExtentsMode */,
3656c2c66affSColin Finck         sizeof(buf) /* ProcessCommandLineInformation */,
3657c2c66affSColin Finck         sizeof(PS_PROTECTION) /* ProcessProtectionInformation */,
3658c2c66affSColin Finck         sizeof(PROCESS_MEMORY_EXHAUSTION_INFO) /* ProcessMemoryExhaustion */,
3659c2c66affSColin Finck         sizeof(PROCESS_FAULT_INFORMATION) /* ProcessFaultInformation */,
3660c2c66affSColin Finck         sizeof(PROCESS_TELEMETRY_ID_INFORMATION) /* ProcessTelemetryIdInformation */,
3661c2c66affSColin Finck         sizeof(PROCESS_COMMIT_RELEASE_INFORMATION) /* ProcessCommitReleaseInformation */,
3662c2c66affSColin Finck         sizeof(?) /* ProcessDefaultCpuSetsInformation */,
3663c2c66affSColin Finck         sizeof(?) /* ProcessAllowedCpuSetsInformation */,
3664c2c66affSColin Finck         0 /* ProcessReserved1Information */,
3665c2c66affSColin Finck         0 /* ProcessReserved2Information */,
3666c2c66affSColin Finck         sizeof(?) /* ProcessSubsystemProcess */,
3667c2c66affSColin Finck         sizeof(PROCESS_JOB_MEMORY_INFO) /* ProcessJobMemoryInformation */,
3668c2c66affSColin Finck #endif
3669c2c66affSColin Finck     };
3670c2c66affSColin Finck     HANDLE hproc;
3671c2c66affSColin Finck     ULONG i, status, ret_len, size;
3672c2c66affSColin Finck 
3673c2c66affSColin Finck     if (!pNtQueryInformationProcess)
3674c2c66affSColin Finck     {
3675c2c66affSColin Finck         win_skip("NtQueryInformationProcess is not available on this platform\n");
3676c2c66affSColin Finck         return;
3677c2c66affSColin Finck     }
3678c2c66affSColin Finck 
3679c2c66affSColin Finck     hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
3680c2c66affSColin Finck     if (!hproc)
3681c2c66affSColin Finck     {
3682c2c66affSColin Finck         win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
3683c2c66affSColin Finck         return;
3684c2c66affSColin Finck     }
3685c2c66affSColin Finck 
3686c2c66affSColin Finck     for (i = 0; i < MaxProcessInfoClass; i++)
3687c2c66affSColin Finck     {
3688c2c66affSColin Finck         size = info_size[i];
3689c2c66affSColin Finck         if (!size) size = sizeof(buf);
3690c2c66affSColin Finck         ret_len = 0;
3691c2c66affSColin Finck         status = pNtQueryInformationProcess(hproc, i, buf, info_size[i], &ret_len);
3692c2c66affSColin Finck         if (status == STATUS_NOT_IMPLEMENTED) continue;
3693c2c66affSColin Finck         if (status == STATUS_INVALID_INFO_CLASS) continue;
3694c2c66affSColin Finck         if (status == STATUS_INFO_LENGTH_MISMATCH) continue;
3695c2c66affSColin Finck 
3696c2c66affSColin Finck         switch (i)
3697c2c66affSColin Finck         {
3698c2c66affSColin Finck         case ProcessBasicInformation:
3699c2c66affSColin Finck         case ProcessQuotaLimits:
3700c2c66affSColin Finck         case ProcessTimes:
3701c2c66affSColin Finck         case ProcessPriorityClass:
3702c2c66affSColin Finck         case ProcessPriorityBoost:
3703c2c66affSColin Finck         case ProcessLUIDDeviceMapsEnabled:
3704c2c66affSColin Finck         case 33 /* ProcessIoPriority */:
3705c2c66affSColin Finck         case ProcessIoCounters:
3706c2c66affSColin Finck         case ProcessVmCounters:
3707c2c66affSColin Finck         case ProcessWow64Information:
3708c2c66affSColin Finck         case ProcessDefaultHardErrorMode:
3709c2c66affSColin Finck         case ProcessHandleCount:
3710c2c66affSColin Finck         case ProcessImageFileName:
3711c2c66affSColin Finck         case ProcessImageInformation:
3712c2c66affSColin Finck         case ProcessPagePriority:
3713c2c66affSColin Finck         case ProcessImageFileNameWin32:
3714c2c66affSColin Finck             ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3715c2c66affSColin Finck             break;
3716c2c66affSColin Finck 
3717c2c66affSColin Finck         case ProcessAffinityMask:
3718c2c66affSColin Finck         case ProcessBreakOnTermination:
3719c2c66affSColin Finck         case ProcessGroupInformation:
3720c2c66affSColin Finck         case ProcessConsoleHostProcess:
3721c2c66affSColin Finck             ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */,
3722c2c66affSColin Finck                "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
3723c2c66affSColin Finck             break;
3724c2c66affSColin Finck 
3725c2c66affSColin Finck         case ProcessDebugObjectHandle:
3726c2c66affSColin Finck             ok(status == STATUS_ACCESS_DENIED || status == STATUS_PORT_NOT_SET,
3727c2c66affSColin Finck                "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3728c2c66affSColin Finck             break;
3729c2c66affSColin Finck 
3730c2c66affSColin Finck         case ProcessExecuteFlags:
3731c2c66affSColin Finck         case ProcessDebugPort:
3732c2c66affSColin Finck         case ProcessDebugFlags:
3733c2c66affSColin Finck         case ProcessCookie:
3734c2c66affSColin Finck todo_wine
3735c2c66affSColin Finck             ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3736c2c66affSColin Finck             break;
3737c2c66affSColin Finck 
3738c2c66affSColin Finck         default:
3739c2c66affSColin Finck             ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
3740c2c66affSColin Finck             break;
3741c2c66affSColin Finck         }
3742c2c66affSColin Finck     }
3743c2c66affSColin Finck 
3744c2c66affSColin Finck     CloseHandle(hproc);
3745c2c66affSColin Finck }
3746c2c66affSColin Finck 
test_GetLogicalProcessorInformationEx(void)3747c2c66affSColin Finck static void test_GetLogicalProcessorInformationEx(void)
3748c2c66affSColin Finck {
3749c2c66affSColin Finck     SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info;
3750c2c66affSColin Finck     DWORD len;
3751c2c66affSColin Finck     BOOL ret;
3752c2c66affSColin Finck 
3753c2c66affSColin Finck     if (!pGetLogicalProcessorInformationEx)
3754c2c66affSColin Finck     {
3755c2c66affSColin Finck         win_skip("GetLogicalProcessorInformationEx() is not supported\n");
3756c2c66affSColin Finck         return;
3757c2c66affSColin Finck     }
3758c2c66affSColin Finck 
3759c2c66affSColin Finck     ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, NULL);
3760c2c66affSColin Finck     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
3761c2c66affSColin Finck 
3762c2c66affSColin Finck     len = 0;
3763c2c66affSColin Finck     ret = pGetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &len);
3764c2c66affSColin Finck     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3765c2c66affSColin Finck     ok(len > 0, "got %u\n", len);
3766c2c66affSColin Finck 
3767c2c66affSColin Finck     len = 0;
3768c2c66affSColin Finck     ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len);
3769c2c66affSColin Finck     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
3770c2c66affSColin Finck     ok(len > 0, "got %u\n", len);
3771c2c66affSColin Finck 
3772c2c66affSColin Finck     info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
3773c2c66affSColin Finck     ret = pGetLogicalProcessorInformationEx(RelationAll, info, &len);
3774c2c66affSColin Finck     ok(ret, "got %d, error %d\n", ret, GetLastError());
3775c2c66affSColin Finck     ok(info->Size > 0, "got %u\n", info->Size);
3776c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, info);
3777c2c66affSColin Finck }
3778c2c66affSColin Finck 
test_largepages(void)3779c2c66affSColin Finck static void test_largepages(void)
3780c2c66affSColin Finck {
3781c2c66affSColin Finck     SIZE_T size;
3782c2c66affSColin Finck 
3783c2c66affSColin Finck     if (!pGetLargePageMinimum) {
3784c2c66affSColin Finck         skip("No GetLargePageMinimum support.\n");
3785c2c66affSColin Finck         return;
3786c2c66affSColin Finck     }
3787c2c66affSColin Finck     size = pGetLargePageMinimum();
3788c2c66affSColin Finck 
3789c2c66affSColin Finck     ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size);
3790c2c66affSColin Finck }
3791c2c66affSColin Finck 
3792c2c66affSColin Finck struct proc_thread_attr
3793c2c66affSColin Finck {
3794c2c66affSColin Finck     DWORD_PTR attr;
3795c2c66affSColin Finck     SIZE_T size;
3796c2c66affSColin Finck     void *value;
3797c2c66affSColin Finck };
3798c2c66affSColin Finck 
3799c2c66affSColin Finck struct _PROC_THREAD_ATTRIBUTE_LIST
3800c2c66affSColin Finck {
3801c2c66affSColin Finck     DWORD mask;  /* bitmask of items in list */
3802c2c66affSColin Finck     DWORD size;  /* max number of items in list */
3803c2c66affSColin Finck     DWORD count; /* number of items in list */
3804c2c66affSColin Finck     DWORD pad;
3805c2c66affSColin Finck     DWORD_PTR unk;
3806c2c66affSColin Finck     struct proc_thread_attr attrs[10];
3807c2c66affSColin Finck };
3808c2c66affSColin Finck 
test_ProcThreadAttributeList(void)3809c2c66affSColin Finck static void test_ProcThreadAttributeList(void)
3810c2c66affSColin Finck {
3811c2c66affSColin Finck     BOOL ret;
3812c2c66affSColin Finck     SIZE_T size, needed;
3813c2c66affSColin Finck     int i;
3814c2c66affSColin Finck     struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list;
3815c2c66affSColin Finck     HANDLE handles[4];
3816c2c66affSColin Finck 
3817c2c66affSColin Finck     if (!pInitializeProcThreadAttributeList)
3818c2c66affSColin Finck     {
3819c2c66affSColin Finck         win_skip("No support for ProcThreadAttributeList\n");
3820c2c66affSColin Finck         return;
3821c2c66affSColin Finck     }
3822c2c66affSColin Finck 
3823c2c66affSColin Finck     for (i = 0; i <= 10; i++)
3824c2c66affSColin Finck     {
3825c2c66affSColin Finck         needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[i]);
3826c2c66affSColin Finck         ret = pInitializeProcThreadAttributeList(NULL, i, 0, &size);
3827c2c66affSColin Finck         ok(!ret, "got %d\n", ret);
3828c2c66affSColin Finck         if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */
3829c2c66affSColin Finck             break;
3830c2c66affSColin Finck         ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
3831c2c66affSColin Finck         ok(size == needed, "%d: got %ld expect %ld\n", i, size, needed);
3832c2c66affSColin Finck 
3833c2c66affSColin Finck         memset(&list, 0xcc, sizeof(list));
3834c2c66affSColin Finck         ret = pInitializeProcThreadAttributeList(&list, i, 0, &size);
3835c2c66affSColin Finck         ok(ret, "got %d\n", ret);
3836c2c66affSColin Finck         ok(list.mask == 0, "%d: got %08x\n", i, list.mask);
3837c2c66affSColin Finck         ok(list.size == i, "%d: got %08x\n", i, list.size);
3838c2c66affSColin Finck         ok(list.count == 0, "%d: got %08x\n", i, list.count);
3839c2c66affSColin Finck         ok(list.unk == 0, "%d: got %08lx\n", i, list.unk);
3840c2c66affSColin Finck     }
3841c2c66affSColin Finck 
3842c2c66affSColin Finck     memset(handles, 0, sizeof(handles));
3843c2c66affSColin Finck     memset(&expect_list, 0xcc, sizeof(expect_list));
3844c2c66affSColin Finck     expect_list.mask = 0;
3845c2c66affSColin Finck     expect_list.size = i - 1;
3846c2c66affSColin Finck     expect_list.count = 0;
3847c2c66affSColin Finck     expect_list.unk = 0;
3848c2c66affSColin Finck 
3849c2c66affSColin Finck     ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3850c2c66affSColin Finck     ok(!ret, "got %d\n", ret);
3851c2c66affSColin Finck     ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %d\n", GetLastError());
3852c2c66affSColin Finck 
3853c2c66affSColin Finck     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL);
3854c2c66affSColin Finck     ok(!ret, "got %d\n", ret);
3855c2c66affSColin Finck     ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3856c2c66affSColin Finck 
3857c2c66affSColin Finck     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL);
3858c2c66affSColin Finck     ok(!ret, "got %d\n", ret);
3859c2c66affSColin Finck     ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3860c2c66affSColin Finck 
3861c2c66affSColin Finck     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3862c2c66affSColin Finck     ok(ret, "got %d\n", ret);
3863c2c66affSColin Finck 
3864c2c66affSColin Finck     expect_list.mask |= 1 << ProcThreadAttributeParentProcess;
3865c2c66affSColin Finck     expect_list.attrs[0].attr = PROC_THREAD_ATTRIBUTE_PARENT_PROCESS;
3866c2c66affSColin Finck     expect_list.attrs[0].size = sizeof(handles[0]);
3867c2c66affSColin Finck     expect_list.attrs[0].value = handles;
3868c2c66affSColin Finck     expect_list.count++;
3869c2c66affSColin Finck 
3870c2c66affSColin Finck     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
3871c2c66affSColin Finck     ok(!ret, "got %d\n", ret);
3872c2c66affSColin Finck     ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3873c2c66affSColin Finck 
3874c2c66affSColin Finck     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL);
3875c2c66affSColin Finck     ok(!ret, "got %d\n", ret);
3876c2c66affSColin Finck     ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
3877c2c66affSColin Finck 
3878c2c66affSColin Finck     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3879c2c66affSColin Finck     ok(ret, "got %d\n", ret);
3880c2c66affSColin Finck 
3881c2c66affSColin Finck     expect_list.mask |= 1 << ProcThreadAttributeHandleList;
3882c2c66affSColin Finck     expect_list.attrs[1].attr = PROC_THREAD_ATTRIBUTE_HANDLE_LIST;
3883c2c66affSColin Finck     expect_list.attrs[1].size = sizeof(handles);
3884c2c66affSColin Finck     expect_list.attrs[1].value = handles;
3885c2c66affSColin Finck     expect_list.count++;
3886c2c66affSColin Finck 
3887c2c66affSColin Finck     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
3888c2c66affSColin Finck     ok(!ret, "got %d\n", ret);
3889c2c66affSColin Finck     ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
3890c2c66affSColin Finck 
3891c2c66affSColin Finck     ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
3892ed41a4deSAmine Khaldi     ok(ret || GetLastError() == ERROR_NOT_SUPPORTED, "got %d gle %d\n", ret, GetLastError());
3893c2c66affSColin Finck 
3894c2c66affSColin Finck     if (ret)
3895c2c66affSColin Finck     {
3896c2c66affSColin Finck         expect_list.mask |= 1 << ProcThreadAttributeIdealProcessor;
3897c2c66affSColin Finck         expect_list.attrs[2].attr = PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR;
3898c2c66affSColin Finck         expect_list.attrs[2].size = sizeof(PROCESSOR_NUMBER);
3899c2c66affSColin Finck         expect_list.attrs[2].value = handles;
3900c2c66affSColin Finck         expect_list.count++;
3901c2c66affSColin Finck     }
3902c2c66affSColin Finck 
3903c2c66affSColin Finck     ok(!memcmp(&list, &expect_list, size), "mismatch\n");
3904c2c66affSColin Finck 
3905c2c66affSColin Finck     pDeleteProcThreadAttributeList(&list);
3906c2c66affSColin Finck }
3907c2c66affSColin Finck 
test_GetActiveProcessorCount(void)3908c2c66affSColin Finck static void test_GetActiveProcessorCount(void)
3909c2c66affSColin Finck {
3910c2c66affSColin Finck     DWORD count;
3911c2c66affSColin Finck 
3912c2c66affSColin Finck     if (!pGetActiveProcessorCount)
3913c2c66affSColin Finck     {
3914c2c66affSColin Finck         win_skip("GetActiveProcessorCount not available, skipping test\n");
3915c2c66affSColin Finck         return;
3916c2c66affSColin Finck     }
3917c2c66affSColin Finck 
3918c2c66affSColin Finck     count = pGetActiveProcessorCount(0);
3919c2c66affSColin Finck     ok(count, "GetActiveProcessorCount failed, error %u\n", GetLastError());
3920c2c66affSColin Finck 
3921c2c66affSColin Finck     /* Test would fail on systems with more than 6400 processors */
3922c2c66affSColin Finck     SetLastError(0xdeadbeef);
3923c2c66affSColin Finck     count = pGetActiveProcessorCount(101);
3924c2c66affSColin Finck     ok(count == 0, "Expeced GetActiveProcessorCount to fail\n");
3925c2c66affSColin Finck     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3926c2c66affSColin Finck }
3927c2c66affSColin Finck 
START_TEST(process)3928c2c66affSColin Finck START_TEST(process)
3929c2c66affSColin Finck {
3930c2c66affSColin Finck     HANDLE job;
3931c2c66affSColin Finck     BOOL b = init();
3932c2c66affSColin Finck     ok(b, "Basic init of CreateProcess test\n");
3933c2c66affSColin Finck     if (!b) return;
3934c2c66affSColin Finck 
3935c2c66affSColin Finck     if (myARGC >= 3)
3936c2c66affSColin Finck     {
3937c2c66affSColin Finck         if (!strcmp(myARGV[2], "dump") && myARGC >= 4)
3938c2c66affSColin Finck         {
3939c2c66affSColin Finck             doChild(myARGV[3], (myARGC >= 5) ? myARGV[4] : NULL);
3940c2c66affSColin Finck             return;
3941c2c66affSColin Finck         }
3942c2c66affSColin Finck         else if (!strcmp(myARGV[2], "wait"))
3943c2c66affSColin Finck         {
3944c2c66affSColin Finck             Sleep(30000);
3945c2c66affSColin Finck             ok(0, "Child process not killed\n");
3946c2c66affSColin Finck             return;
3947c2c66affSColin Finck         }
3948c2c66affSColin Finck         else if (!strcmp(myARGV[2], "exit"))
3949c2c66affSColin Finck         {
3950c2c66affSColin Finck             Sleep(100);
3951c2c66affSColin Finck             return;
3952c2c66affSColin Finck         }
3953c2c66affSColin Finck         else if (!strcmp(myARGV[2], "nested") && myARGC >= 4)
3954c2c66affSColin Finck         {
3955c2c66affSColin Finck             char                buffer[MAX_PATH];
3956c2c66affSColin Finck             STARTUPINFOA        startup;
3957c2c66affSColin Finck             PROCESS_INFORMATION info;
3958c2c66affSColin Finck 
3959c2c66affSColin Finck             memset(&startup, 0, sizeof(startup));
3960c2c66affSColin Finck             startup.cb = sizeof(startup);
3961c2c66affSColin Finck             startup.dwFlags = STARTF_USESHOWWINDOW;
3962c2c66affSColin Finck             startup.wShowWindow = SW_SHOWNORMAL;
3963c2c66affSColin Finck 
3964c2c66affSColin Finck             sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, myARGV[3]);
3965c2c66affSColin Finck             ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess failed\n");
3966c2c66affSColin Finck             CloseHandle(info.hProcess);
3967c2c66affSColin Finck             CloseHandle(info.hThread);
3968c2c66affSColin Finck             return;
3969c2c66affSColin Finck         }
3970c2c66affSColin Finck 
3971c2c66affSColin Finck         ok(0, "Unexpected command %s\n", myARGV[2]);
3972c2c66affSColin Finck         return;
3973c2c66affSColin Finck     }
3974c2c66affSColin Finck 
3975c2c66affSColin Finck     test_process_info();
3976c2c66affSColin Finck     test_TerminateProcess();
3977c2c66affSColin Finck     test_Startup();
3978c2c66affSColin Finck     test_CommandLine();
3979c2c66affSColin Finck     test_Directory();
3980*8a437ac5STimo Kreuzer     test_Toolhelp(); //
3981c2c66affSColin Finck     test_Environment();
3982c2c66affSColin Finck     test_SuspendFlag();
3983c2c66affSColin Finck     test_DebuggingFlag();
3984c2c66affSColin Finck     test_Console();
3985c2c66affSColin Finck     test_ExitCode();
3986c2c66affSColin Finck     test_OpenProcess();
3987c2c66affSColin Finck     test_GetProcessVersion();
3988c2c66affSColin Finck     test_GetProcessImageFileNameA();
3989c2c66affSColin Finck     test_QueryFullProcessImageNameA();
3990c2c66affSColin Finck     test_QueryFullProcessImageNameW();
3991c2c66affSColin Finck     test_Handles();
3992c2c66affSColin Finck     test_IsWow64Process();
3993c2c66affSColin Finck     test_SystemInfo();
3994c2c66affSColin Finck     test_RegistryQuota();
3995c2c66affSColin Finck     test_DuplicateHandle();
3996c2c66affSColin Finck     test_StartupNoConsole();
3997c2c66affSColin Finck     test_DetachConsoleHandles();
3998c2c66affSColin Finck     test_DetachStdHandles();
3999c2c66affSColin Finck     test_GetNumaProcessorNode();
4000c2c66affSColin Finck     test_session_info();
4001c2c66affSColin Finck     test_GetLogicalProcessorInformationEx();
4002c2c66affSColin Finck     test_GetActiveProcessorCount();
4003c2c66affSColin Finck     test_largepages();
4004c2c66affSColin Finck     test_ProcThreadAttributeList();
4005ed41a4deSAmine Khaldi     test_SuspendProcessState();
4006ed41a4deSAmine Khaldi     test_SuspendProcessNewThread();
4007c2c66affSColin Finck 
4008c2c66affSColin Finck     /* things that can be tested:
4009c2c66affSColin Finck      *  lookup:         check the way program to be executed is searched
4010c2c66affSColin Finck      *  handles:        check the handle inheritance stuff (+sec options)
4011c2c66affSColin Finck      *  console:        check if console creation parameters work
4012c2c66affSColin Finck      */
4013c2c66affSColin Finck 
4014c2c66affSColin Finck     if (!pCreateJobObjectW)
4015c2c66affSColin Finck     {
4016c2c66affSColin Finck         win_skip("No job object support\n");
4017c2c66affSColin Finck         return;
4018c2c66affSColin Finck     }
4019c2c66affSColin Finck 
4020c2c66affSColin Finck     test_IsProcessInJob();
4021c2c66affSColin Finck     test_TerminateJobObject();
4022c2c66affSColin Finck     test_QueryInformationJobObject();
4023c2c66affSColin Finck     test_CompletionPort();
4024c2c66affSColin Finck     test_KillOnJobClose();
4025c2c66affSColin Finck     test_WaitForJobObject();
4026c2c66affSColin Finck     job = test_AddSelfToJob();
4027c2c66affSColin Finck     test_jobInheritance(job);
4028c2c66affSColin Finck     test_BreakawayOk(job);
4029c2c66affSColin Finck     CloseHandle(job);
4030c2c66affSColin Finck }
4031