2 * Unit test suite for process functions
4 * Copyright 2002 Eric Pouech
5 * Copyright 2006 Dmitry Timoshkov
6 * Copyright 2014 Michael Müller
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #define WIN32_NO_STATUS
37 #include "wine/test.h"
39 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
40 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
42 #define expect_eq_d(expected, actual) \
44 int value = (actual); \
45 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
48 #define expect_eq_s(expected, actual) \
50 LPCSTR value = (actual); \
51 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
54 #define expect_eq_ws_i(expected, actual) \
56 LPCWSTR value = (actual); \
57 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
58 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
61 static HINSTANCE hkernel32
, hntdll
;
62 static void (WINAPI
*pGetNativeSystemInfo
)(LPSYSTEM_INFO
);
63 static BOOL (WINAPI
*pGetSystemRegistryQuota
)(PDWORD
, PDWORD
);
64 static BOOL (WINAPI
*pIsWow64Process
)(HANDLE
,PBOOL
);
65 static LPVOID (WINAPI
*pVirtualAllocEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
, DWORD
);
66 static BOOL (WINAPI
*pVirtualFreeEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
);
67 static BOOL (WINAPI
*pQueryFullProcessImageNameA
)(HANDLE hProcess
, DWORD dwFlags
, LPSTR lpExeName
, PDWORD lpdwSize
);
68 static BOOL (WINAPI
*pQueryFullProcessImageNameW
)(HANDLE hProcess
, DWORD dwFlags
, LPWSTR lpExeName
, PDWORD lpdwSize
);
69 static DWORD (WINAPI
*pK32GetProcessImageFileNameA
)(HANDLE
,LPSTR
,DWORD
);
70 static struct _TEB
* (WINAPI
*pNtCurrentTeb
)(void);
71 static HANDLE (WINAPI
*pCreateJobObjectW
)(LPSECURITY_ATTRIBUTES sa
, LPCWSTR name
);
72 static BOOL (WINAPI
*pAssignProcessToJobObject
)(HANDLE job
, HANDLE process
);
73 static BOOL (WINAPI
*pIsProcessInJob
)(HANDLE process
, HANDLE job
, PBOOL result
);
74 static BOOL (WINAPI
*pTerminateJobObject
)(HANDLE job
, UINT exit_code
);
75 static BOOL (WINAPI
*pQueryInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
, LPDWORD ret_len
);
76 static BOOL (WINAPI
*pSetInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
);
77 static HANDLE (WINAPI
*pCreateIoCompletionPort
)(HANDLE file
, HANDLE existing_port
, ULONG_PTR key
, DWORD threads
);
78 static BOOL (WINAPI
*pGetNumaProcessorNode
)(UCHAR
, PUCHAR
);
79 static NTSTATUS (WINAPI
*pNtQueryInformationProcess
)(HANDLE
, PROCESSINFOCLASS
, PVOID
, ULONG
, PULONG
);
80 static BOOL (WINAPI
*pProcessIdToSessionId
)(DWORD
,DWORD
*);
81 static DWORD (WINAPI
*pWTSGetActiveConsoleSessionId
)(void);
83 /* ############################### */
84 static char base
[MAX_PATH
];
85 static char selfname
[MAX_PATH
];
87 static char resfile
[MAX_PATH
];
92 /* As some environment variables get very long on Unix, we only test for
93 * the first 127 bytes.
94 * Note that increasing this value past 256 may exceed the buffer size
95 * limitations of the *Profile functions (at least on Wine).
97 #define MAX_LISTED_ENV_VAR 128
99 /* ---------------- portable memory allocation thingie */
101 static char memory
[1024*256];
102 static char* memory_index
= memory
;
104 static char* grab_memory(size_t len
)
106 char* ret
= memory_index
;
108 len
= (len
+ 3) & ~3;
110 assert(memory_index
<= memory
+ sizeof(memory
));
114 static void release_memory(void)
116 memory_index
= memory
;
119 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
121 static const char* encodeA(const char* str
)
127 len
= strlen(str
) + 1;
128 ptr
= grab_memory(len
* 2 + 1);
129 for (i
= 0; i
< len
; i
++)
130 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
135 static const char* encodeW(const WCHAR
* str
)
141 len
= lstrlenW(str
) + 1;
142 ptr
= grab_memory(len
* 4 + 1);
144 for (i
= 0; i
< len
; i
++)
145 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
150 static unsigned decode_char(char c
)
152 if (c
>= '0' && c
<= '9') return c
- '0';
153 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
154 assert(c
>= 'A' && c
<= 'F');
158 static char* decodeA(const char* str
)
163 len
= strlen(str
) / 2;
164 if (!len
--) return NULL
;
165 ptr
= grab_memory(len
+ 1);
166 for (i
= 0; i
< len
; i
++)
167 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
172 /* This will be needed to decode Unicode strings saved by the child process
173 * when we test Unicode functions.
175 static WCHAR
* decodeW(const char* str
)
181 len
= strlen(str
) / 4;
182 if (!len
--) return NULL
;
183 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
184 for (i
= 0; i
< len
; i
++)
185 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
186 (decode_char(str
[4 * i
+ 1]) << 8) |
187 (decode_char(str
[4 * i
+ 2]) << 4) |
188 (decode_char(str
[4 * i
+ 3]) << 0);
193 /******************************************************************
196 * generates basic information like:
197 * base: absolute path to curr dir
198 * selfname: the way to reinvoke ourselves
199 * exename: executable without the path
200 * function-pointers, which are not implemented in all windows versions
202 static BOOL
init(void)
206 myARGC
= winetest_get_mainargs( &myARGV
);
207 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return FALSE
;
208 strcpy(selfname
, myARGV
[0]);
210 /* Strip the path of selfname */
211 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
212 else exename
= selfname
;
214 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
216 hkernel32
= GetModuleHandleA("kernel32");
217 hntdll
= GetModuleHandleA("ntdll.dll");
219 pNtCurrentTeb
= (void *)GetProcAddress(hntdll
, "NtCurrentTeb");
220 pNtQueryInformationProcess
= (void *)GetProcAddress(hntdll
, "NtQueryInformationProcess");
222 pGetNativeSystemInfo
= (void *) GetProcAddress(hkernel32
, "GetNativeSystemInfo");
223 pGetSystemRegistryQuota
= (void *) GetProcAddress(hkernel32
, "GetSystemRegistryQuota");
224 pIsWow64Process
= (void *) GetProcAddress(hkernel32
, "IsWow64Process");
225 pVirtualAllocEx
= (void *) GetProcAddress(hkernel32
, "VirtualAllocEx");
226 pVirtualFreeEx
= (void *) GetProcAddress(hkernel32
, "VirtualFreeEx");
227 pQueryFullProcessImageNameA
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameA");
228 pQueryFullProcessImageNameW
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameW");
229 pK32GetProcessImageFileNameA
= (void *) GetProcAddress(hkernel32
, "K32GetProcessImageFileNameA");
230 pCreateJobObjectW
= (void *)GetProcAddress(hkernel32
, "CreateJobObjectW");
231 pAssignProcessToJobObject
= (void *)GetProcAddress(hkernel32
, "AssignProcessToJobObject");
232 pIsProcessInJob
= (void *)GetProcAddress(hkernel32
, "IsProcessInJob");
233 pTerminateJobObject
= (void *)GetProcAddress(hkernel32
, "TerminateJobObject");
234 pQueryInformationJobObject
= (void *)GetProcAddress(hkernel32
, "QueryInformationJobObject");
235 pSetInformationJobObject
= (void *)GetProcAddress(hkernel32
, "SetInformationJobObject");
236 pCreateIoCompletionPort
= (void *)GetProcAddress(hkernel32
, "CreateIoCompletionPort");
237 pGetNumaProcessorNode
= (void *)GetProcAddress(hkernel32
, "GetNumaProcessorNode");
238 pProcessIdToSessionId
= (void *)GetProcAddress(hkernel32
, "ProcessIdToSessionId");
239 pWTSGetActiveConsoleSessionId
= (void *)GetProcAddress(hkernel32
, "WTSGetActiveConsoleSessionId");
243 /******************************************************************
246 * generates an absolute file_name for temporary file
249 static void get_file_name(char* buf
)
254 GetTempPathA(sizeof(path
), path
);
255 GetTempFileNameA(path
, "wt", 0, buf
);
258 /******************************************************************
259 * static void childPrintf
262 static void childPrintf(HANDLE h
, const char* fmt
, ...)
265 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
268 va_start(valist
, fmt
);
269 vsprintf(buffer
, fmt
, valist
);
271 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
275 /******************************************************************
278 * output most of the information in the child process
280 static void doChild(const char* file
, const char* option
)
285 char *ptrA
, *ptrA_save
;
286 WCHAR
*ptrW
, *ptrW_save
;
288 WCHAR bufW
[MAX_PATH
];
289 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
292 if (hFile
== INVALID_HANDLE_VALUE
) return;
294 /* output of startup info (Ansi) */
295 GetStartupInfoA(&siA
);
297 "[StartupInfoA]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
298 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
299 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
300 "dwFlags=%lu\nwShowWindow=%u\n"
301 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
302 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
303 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
304 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
305 siA
.dwFlags
, siA
.wShowWindow
,
306 (DWORD_PTR
)siA
.hStdInput
, (DWORD_PTR
)siA
.hStdOutput
, (DWORD_PTR
)siA
.hStdError
);
310 RTL_USER_PROCESS_PARAMETERS
*params
= pNtCurrentTeb()->Peb
->ProcessParameters
;
312 /* check the console handles in the TEB */
313 childPrintf(hFile
, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
314 (DWORD_PTR
)params
->hStdInput
, (DWORD_PTR
)params
->hStdOutput
,
315 (DWORD_PTR
)params
->hStdError
);
318 /* since GetStartupInfoW is only implemented in win2k,
319 * zero out before calling so we can notice the difference
321 memset(&siW
, 0, sizeof(siW
));
322 GetStartupInfoW(&siW
);
324 "[StartupInfoW]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
325 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
326 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
327 "dwFlags=%lu\nwShowWindow=%u\n"
328 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
329 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
330 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
331 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
332 siW
.dwFlags
, siW
.wShowWindow
,
333 (DWORD_PTR
)siW
.hStdInput
, (DWORD_PTR
)siW
.hStdOutput
, (DWORD_PTR
)siW
.hStdError
);
336 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
337 for (i
= 0; i
< myARGC
; i
++)
339 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
341 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
342 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
344 /* output of environment (Ansi) */
345 ptrA_save
= ptrA
= GetEnvironmentStringsA();
348 char env_var
[MAX_LISTED_ENV_VAR
];
350 childPrintf(hFile
, "[EnvironmentA]\n");
354 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
355 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
357 ptrA
+= strlen(ptrA
) + 1;
359 childPrintf(hFile
, "len=%d\n\n", i
);
360 FreeEnvironmentStringsA(ptrA_save
);
363 /* output of environment (Unicode) */
364 ptrW_save
= ptrW
= GetEnvironmentStringsW();
367 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
369 childPrintf(hFile
, "[EnvironmentW]\n");
373 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
374 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
375 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
377 ptrW
+= lstrlenW(ptrW
) + 1;
379 childPrintf(hFile
, "len=%d\n\n", i
);
380 FreeEnvironmentStringsW(ptrW_save
);
383 childPrintf(hFile
, "[Misc]\n");
384 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
385 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
386 if (GetCurrentDirectoryW(sizeof(bufW
) / sizeof(bufW
[0]), bufW
))
387 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
388 childPrintf(hFile
, "\n");
390 if (option
&& strcmp(option
, "console") == 0)
392 CONSOLE_SCREEN_BUFFER_INFO sbi
;
393 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
394 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
395 DWORD modeIn
, modeOut
;
397 childPrintf(hFile
, "[Console]\n");
398 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
400 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
401 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
402 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
403 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
404 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
405 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
407 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
408 GetConsoleCP(), GetConsoleOutputCP());
409 if (GetConsoleMode(hConIn
, &modeIn
))
410 childPrintf(hFile
, "InputMode=%ld\n", modeIn
);
411 if (GetConsoleMode(hConOut
, &modeOut
))
412 childPrintf(hFile
, "OutputMode=%ld\n", modeOut
);
414 /* now that we have written all relevant information, let's change it */
415 SetLastError(0xdeadbeef);
416 ret
= SetConsoleCP(1252);
417 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
419 win_skip("Setting the codepage is not implemented\n");
423 ok(ret
, "Setting CP\n");
424 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
427 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
428 ok( ret
, "Setting mode (%d)\n", GetLastError());
429 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
430 ok( ret
, "Setting mode (%d)\n", GetLastError());
431 sbi
.dwCursorPosition
.X
^= 1;
432 sbi
.dwCursorPosition
.Y
^= 1;
433 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
434 ok( ret
, "Setting cursor position (%d)\n", GetLastError());
436 if (option
&& strcmp(option
, "stdhandle") == 0)
438 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
439 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
441 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
446 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
447 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
448 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
452 if (option
&& strcmp(option
, "exit_code") == 0)
454 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
462 static char* getChildString(const char* sect
, const char* key
)
464 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
467 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
468 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
469 assert(!(strlen(buf
) & 1));
474 static WCHAR
* getChildStringW(const char* sect
, const char* key
)
476 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
479 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
480 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
481 assert(!(strlen(buf
) & 1));
486 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
487 * others... (windows uses stricmp while Un*x uses strcasecmp...)
489 static int wtstrcasecmp(const char* p1
, const char* p2
)
494 while (c1
== c2
&& c1
)
496 c1
= *p1
++; c2
= *p2
++;
499 c1
= toupper(c1
); c2
= toupper(c2
);
505 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
507 if (!s1
&& !s2
) return 0;
510 return (sensitive
) ? strcmp(s1
, s2
) : wtstrcasecmp(s1
, s2
);
513 static void ok_child_string( int line
, const char *sect
, const char *key
,
514 const char *expect
, int sensitive
)
516 char* result
= getChildString( sect
, key
);
517 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
518 sect
, key
, expect
? expect
: "(null)", result
);
521 static void ok_child_stringWA( int line
, const char *sect
, const char *key
,
522 const char *expect
, int sensitive
)
527 WCHAR
* result
= getChildStringW( sect
, key
);
529 len
= MultiByteToWideChar( CP_ACP
, 0, expect
, -1, NULL
, 0);
530 expectW
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
531 MultiByteToWideChar( CP_ACP
, 0, expect
, -1, expectW
, len
);
533 len
= WideCharToMultiByte( CP_ACP
, 0, result
, -1, NULL
, 0, NULL
, NULL
);
534 resultA
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(CHAR
));
535 WideCharToMultiByte( CP_ACP
, 0, result
, -1, resultA
, len
, NULL
, NULL
);
538 ok_(__FILE__
, line
)( lstrcmpW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
539 sect
, key
, expect
? expect
: "(null)", resultA
);
541 ok_(__FILE__
, line
)( lstrcmpiW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
542 sect
, key
, expect
? expect
: "(null)", resultA
);
543 HeapFree(GetProcessHeap(),0,expectW
);
544 HeapFree(GetProcessHeap(),0,resultA
);
547 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
548 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
549 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
551 /* using !expect ensures that the test will fail if the sect/key isn't present
554 #define okChildInt(sect, key, expect) \
556 UINT result = GetPrivateProfileIntA((sect), (key), !(expect), resfile); \
557 ok(result == expect, "%s:%s expected %u, but got %u\n", (sect), (key), (UINT)(expect), result); \
560 static void test_Startup(void)
562 char buffer
[MAX_PATH
];
563 PROCESS_INFORMATION info
;
564 STARTUPINFOA startup
,si
;
566 static CHAR title
[] = "I'm the title string",
567 desktop
[] = "winsta0\\default",
570 /* let's start simplistic */
571 memset(&startup
, 0, sizeof(startup
));
572 startup
.cb
= sizeof(startup
);
573 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
574 startup
.wShowWindow
= SW_SHOWNORMAL
;
576 get_file_name(resfile
);
577 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
578 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
579 /* wait for child to terminate */
580 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
581 /* child process has changed result file, so let profile functions know about it */
582 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
584 GetStartupInfoA(&si
);
585 okChildInt("StartupInfoA", "cb", startup
.cb
);
586 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
587 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
588 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
589 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
590 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
591 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
592 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
593 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
594 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
595 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
597 assert(DeleteFileA(resfile
) != 0);
599 /* not so simplistic now */
600 memset(&startup
, 0, sizeof(startup
));
601 startup
.cb
= sizeof(startup
);
602 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
603 startup
.wShowWindow
= SW_SHOWNORMAL
;
604 startup
.lpTitle
= title
;
605 startup
.lpDesktop
= desktop
;
606 startup
.dwXCountChars
= 0x12121212;
607 startup
.dwYCountChars
= 0x23232323;
608 startup
.dwX
= 0x34343434;
609 startup
.dwY
= 0x45454545;
610 startup
.dwXSize
= 0x56565656;
611 startup
.dwYSize
= 0x67676767;
612 startup
.dwFillAttribute
= 0xA55A;
614 get_file_name(resfile
);
615 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
616 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
617 /* wait for child to terminate */
618 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
619 /* child process has changed result file, so let profile functions know about it */
620 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
622 okChildInt("StartupInfoA", "cb", startup
.cb
);
623 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
624 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
625 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
626 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
627 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
628 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
629 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
630 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
631 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
632 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
633 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
635 assert(DeleteFileA(resfile
) != 0);
637 /* not so simplistic now */
638 memset(&startup
, 0, sizeof(startup
));
639 startup
.cb
= sizeof(startup
);
640 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
641 startup
.wShowWindow
= SW_SHOWNORMAL
;
642 startup
.lpTitle
= title
;
643 startup
.lpDesktop
= NULL
;
644 startup
.dwXCountChars
= 0x12121212;
645 startup
.dwYCountChars
= 0x23232323;
646 startup
.dwX
= 0x34343434;
647 startup
.dwY
= 0x45454545;
648 startup
.dwXSize
= 0x56565656;
649 startup
.dwYSize
= 0x67676767;
650 startup
.dwFillAttribute
= 0xA55A;
652 get_file_name(resfile
);
653 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
654 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
655 /* wait for child to terminate */
656 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
657 /* child process has changed result file, so let profile functions know about it */
658 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
660 okChildInt("StartupInfoA", "cb", startup
.cb
);
661 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
662 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
663 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
664 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
665 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
666 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
667 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
668 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
669 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
670 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
671 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
673 assert(DeleteFileA(resfile
) != 0);
675 /* not so simplistic now */
676 memset(&startup
, 0, sizeof(startup
));
677 startup
.cb
= sizeof(startup
);
678 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
679 startup
.wShowWindow
= SW_SHOWNORMAL
;
680 startup
.lpTitle
= title
;
681 startup
.lpDesktop
= empty
;
682 startup
.dwXCountChars
= 0x12121212;
683 startup
.dwYCountChars
= 0x23232323;
684 startup
.dwX
= 0x34343434;
685 startup
.dwY
= 0x45454545;
686 startup
.dwXSize
= 0x56565656;
687 startup
.dwYSize
= 0x67676767;
688 startup
.dwFillAttribute
= 0xA55A;
690 get_file_name(resfile
);
691 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
692 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
693 /* wait for child to terminate */
694 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
695 /* child process has changed result file, so let profile functions know about it */
696 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
698 okChildInt("StartupInfoA", "cb", startup
.cb
);
699 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
700 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
701 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
702 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
703 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
704 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
705 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
706 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
707 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
708 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
709 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
711 assert(DeleteFileA(resfile
) != 0);
713 /* not so simplistic now */
714 memset(&startup
, 0, sizeof(startup
));
715 startup
.cb
= sizeof(startup
);
716 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
717 startup
.wShowWindow
= SW_SHOWNORMAL
;
718 startup
.lpTitle
= NULL
;
719 startup
.lpDesktop
= desktop
;
720 startup
.dwXCountChars
= 0x12121212;
721 startup
.dwYCountChars
= 0x23232323;
722 startup
.dwX
= 0x34343434;
723 startup
.dwY
= 0x45454545;
724 startup
.dwXSize
= 0x56565656;
725 startup
.dwYSize
= 0x67676767;
726 startup
.dwFillAttribute
= 0xA55A;
728 get_file_name(resfile
);
729 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
730 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
731 /* wait for child to terminate */
732 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
733 /* child process has changed result file, so let profile functions know about it */
734 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
736 okChildInt("StartupInfoA", "cb", startup
.cb
);
737 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
738 result
= getChildString( "StartupInfoA", "lpTitle" );
739 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
740 "expected '%s' or null, got '%s'\n", selfname
, result
);
741 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
742 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
743 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
744 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
745 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
746 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
747 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
748 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
749 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
751 assert(DeleteFileA(resfile
) != 0);
753 /* not so simplistic now */
754 memset(&startup
, 0, sizeof(startup
));
755 startup
.cb
= sizeof(startup
);
756 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
757 startup
.wShowWindow
= SW_SHOWNORMAL
;
758 startup
.lpTitle
= empty
;
759 startup
.lpDesktop
= desktop
;
760 startup
.dwXCountChars
= 0x12121212;
761 startup
.dwYCountChars
= 0x23232323;
762 startup
.dwX
= 0x34343434;
763 startup
.dwY
= 0x45454545;
764 startup
.dwXSize
= 0x56565656;
765 startup
.dwYSize
= 0x67676767;
766 startup
.dwFillAttribute
= 0xA55A;
768 get_file_name(resfile
);
769 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
770 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
771 /* wait for child to terminate */
772 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
773 /* child process has changed result file, so let profile functions know about it */
774 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
776 okChildInt("StartupInfoA", "cb", startup
.cb
);
777 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
778 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
779 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
780 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
781 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
782 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
783 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
784 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
785 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
786 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
787 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
789 assert(DeleteFileA(resfile
) != 0);
791 /* not so simplistic now */
792 memset(&startup
, 0, sizeof(startup
));
793 startup
.cb
= sizeof(startup
);
794 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
795 startup
.wShowWindow
= SW_SHOWNORMAL
;
796 startup
.lpTitle
= empty
;
797 startup
.lpDesktop
= empty
;
798 startup
.dwXCountChars
= 0x12121212;
799 startup
.dwYCountChars
= 0x23232323;
800 startup
.dwX
= 0x34343434;
801 startup
.dwY
= 0x45454545;
802 startup
.dwXSize
= 0x56565656;
803 startup
.dwYSize
= 0x67676767;
804 startup
.dwFillAttribute
= 0xA55A;
806 get_file_name(resfile
);
807 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
808 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
809 /* wait for child to terminate */
810 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
811 /* child process has changed result file, so let profile functions know about it */
812 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
814 okChildInt("StartupInfoA", "cb", startup
.cb
);
815 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
816 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
817 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
818 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
819 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
820 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
821 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
822 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
823 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
824 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
825 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
827 assert(DeleteFileA(resfile
) != 0);
829 /* TODO: test for A/W and W/A and W/W */
832 static void test_CommandLine(void)
834 char buffer
[MAX_PATH
], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
835 char buffer2
[MAX_PATH
];
836 PROCESS_INFORMATION info
;
837 STARTUPINFOA startup
;
840 memset(&startup
, 0, sizeof(startup
));
841 startup
.cb
= sizeof(startup
);
842 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
843 startup
.wShowWindow
= SW_SHOWNORMAL
;
846 get_file_name(resfile
);
847 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
848 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
849 /* wait for child to terminate */
850 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
851 /* child process has changed result file, so let profile functions know about it */
852 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
854 okChildInt("Arguments", "argcA", 5);
855 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
856 okChildString("Arguments", "argvA5", NULL
);
857 okChildString("Arguments", "CommandLineA", buffer
);
859 assert(DeleteFileA(resfile
) != 0);
861 memset(&startup
, 0, sizeof(startup
));
862 startup
.cb
= sizeof(startup
);
863 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
864 startup
.wShowWindow
= SW_SHOWNORMAL
;
867 get_file_name(resfile
);
868 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname
, resfile
);
869 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
870 /* wait for child to terminate */
871 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
872 /* child process has changed result file, so let profile functions know about it */
873 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
875 okChildInt("Arguments", "argcA", 7);
876 okChildString("Arguments", "argvA4", "a\"b\\");
877 okChildString("Arguments", "argvA5", "c\"");
878 okChildString("Arguments", "argvA6", "d");
879 okChildString("Arguments", "argvA7", NULL
);
880 okChildString("Arguments", "CommandLineA", buffer
);
882 assert(DeleteFileA(resfile
) != 0);
884 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
885 get_file_name(resfile
);
886 /* Use exename to avoid buffer containing things like 'C:' */
887 sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
888 SetLastError(0xdeadbeef);
889 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
890 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
891 /* wait for child to terminate */
892 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
893 /* child process has changed result file, so let profile functions know about it */
894 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
895 sprintf(buffer
, "./%s", exename
);
896 okChildString("Arguments", "argvA0", buffer
);
898 assert(DeleteFileA(resfile
) != 0);
900 get_file_name(resfile
);
901 /* Use exename to avoid buffer containing things like 'C:' */
902 sprintf(buffer
, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
903 SetLastError(0xdeadbeef);
904 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
905 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
906 /* wait for child to terminate */
907 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
908 /* child process has changed result file, so let profile functions know about it */
909 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
910 sprintf(buffer
, ".\\%s", exename
);
911 okChildString("Arguments", "argvA0", buffer
);
913 assert(DeleteFileA(resfile
) != 0);
915 get_file_name(resfile
);
916 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
917 assert ( lpFilePart
!= 0);
918 *(lpFilePart
-1 ) = 0;
919 p
= strrchr(fullpath
, '\\');
920 /* Use exename to avoid buffer containing things like 'C:' */
921 if (p
) sprintf(buffer
, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p
, exename
, resfile
);
922 else sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
923 SetLastError(0xdeadbeef);
924 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
925 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
926 /* wait for child to terminate */
927 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
928 /* child process has changed result file, so let profile functions know about it */
929 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
930 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
931 else sprintf(buffer
, "./%s", exename
);
932 okChildString("Arguments", "argvA0", buffer
);
934 assert(DeleteFileA(resfile
) != 0);
937 get_file_name(resfile
);
938 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
939 assert ( lpFilePart
!= 0);
940 *(lpFilePart
-1 ) = 0;
941 p
= strrchr(fullpath
, '\\');
942 /* Use exename to avoid buffer containing things like 'C:' */
943 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
944 else sprintf(buffer
, "./%s", exename
);
945 sprintf(buffer2
, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile
);
946 SetLastError(0xdeadbeef);
947 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
948 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
949 /* wait for child to terminate */
950 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
951 /* child process has changed result file, so let profile functions know about it */
952 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
953 sprintf(buffer
, "tests/process.c dump %s", resfile
);
954 okChildString("Arguments", "argvA0", "dummy");
955 okChildString("Arguments", "CommandLineA", buffer2
);
956 okChildStringWA("Arguments", "CommandLineW", buffer2
);
958 assert(DeleteFileA(resfile
) != 0);
960 if (0) /* Test crashes on NT-based Windows. */
962 /* Test NULL application name and command line parameters. */
963 SetLastError(0xdeadbeef);
964 ret
= CreateProcessA(NULL
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
965 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
966 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
967 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
972 /* Test empty application name parameter. */
973 SetLastError(0xdeadbeef);
974 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
975 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
976 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
977 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
978 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
979 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
983 /* Test empty application name and command line parameters. */
984 SetLastError(0xdeadbeef);
985 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
986 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
987 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
988 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
989 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
990 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
992 /* Test empty command line parameter. */
993 SetLastError(0xdeadbeef);
994 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
995 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
996 ok(GetLastError() == ERROR_FILE_NOT_FOUND
||
997 GetLastError() == ERROR_PATH_NOT_FOUND
/* NT4 */ ||
998 GetLastError() == ERROR_BAD_PATHNAME
/* Win98 */ ||
999 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7 */,
1000 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1002 strcpy(buffer
, "doesnotexist.exe");
1003 strcpy(buffer2
, "does not exist.exe");
1005 /* Test nonexistent application name. */
1006 SetLastError(0xdeadbeef);
1007 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1008 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1009 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1011 SetLastError(0xdeadbeef);
1012 ret
= CreateProcessA(buffer2
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1013 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1014 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1016 /* Test nonexistent command line parameter. */
1017 SetLastError(0xdeadbeef);
1018 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1019 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1020 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1022 SetLastError(0xdeadbeef);
1023 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1024 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1025 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1028 static void test_Directory(void)
1030 char buffer
[MAX_PATH
];
1031 PROCESS_INFORMATION info
;
1032 STARTUPINFOA startup
;
1033 char windir
[MAX_PATH
];
1034 static CHAR cmdline
[] = "winver.exe";
1036 memset(&startup
, 0, sizeof(startup
));
1037 startup
.cb
= sizeof(startup
);
1038 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1039 startup
.wShowWindow
= SW_SHOWNORMAL
;
1042 get_file_name(resfile
);
1043 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1044 GetWindowsDirectoryA( windir
, sizeof(windir
) );
1045 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
1046 /* wait for child to terminate */
1047 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1048 /* child process has changed result file, so let profile functions know about it */
1049 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1051 okChildIString("Misc", "CurrDirA", windir
);
1053 assert(DeleteFileA(resfile
) != 0);
1055 /* search PATH for the exe if directory is NULL */
1056 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1057 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
1059 /* if any directory is provided, don't search PATH, error on bad directory */
1060 SetLastError(0xdeadbeef);
1061 memset(&info
, 0, sizeof(info
));
1062 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
1063 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
1064 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1065 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
1068 static BOOL
is_str_env_drive_dir(const char* str
)
1070 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1071 str
[3] == '=' && str
[4] == str
[1];
1074 /* compared expected child's environment (in gesA) from actual
1075 * environment our child got
1077 static void cmpEnvironment(const char* gesA
)
1085 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1087 /* now look each parent env in child */
1088 if ((ptrA
= gesA
) != NULL
)
1092 for (i
= 0; i
< clen
; i
++)
1094 sprintf(key
, "env%d", i
);
1095 res
= getChildString("EnvironmentA", key
);
1096 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1100 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1102 ptrA
+= strlen(ptrA
) + 1;
1106 /* and each child env in parent */
1107 for (i
= 0; i
< clen
; i
++)
1109 sprintf(key
, "env%d", i
);
1110 res
= getChildString("EnvironmentA", key
);
1111 if ((ptrA
= gesA
) != NULL
)
1115 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1117 ptrA
+= strlen(ptrA
) + 1;
1119 if (!*ptrA
) ptrA
= NULL
;
1122 if (!is_str_env_drive_dir(res
))
1124 found
= ptrA
!= NULL
;
1125 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1127 /* else => should also test we get the right per drive default directory here... */
1131 static void test_Environment(void)
1133 char buffer
[MAX_PATH
];
1134 PROCESS_INFORMATION info
;
1135 STARTUPINFOA startup
;
1143 memset(&startup
, 0, sizeof(startup
));
1144 startup
.cb
= sizeof(startup
);
1145 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1146 startup
.wShowWindow
= SW_SHOWNORMAL
;
1149 get_file_name(resfile
);
1150 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1151 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1152 /* wait for child to terminate */
1153 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1154 /* child process has changed result file, so let profile functions know about it */
1155 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1157 env
= GetEnvironmentStringsA();
1158 cmpEnvironment(env
);
1160 assert(DeleteFileA(resfile
) != 0);
1162 memset(&startup
, 0, sizeof(startup
));
1163 startup
.cb
= sizeof(startup
);
1164 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1165 startup
.wShowWindow
= SW_SHOWNORMAL
;
1168 get_file_name(resfile
);
1169 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1175 slen
= strlen(ptr
)+1;
1176 child_env_len
+= slen
;
1179 /* Add space for additional environment variables */
1180 child_env_len
+= 256;
1181 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1184 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1185 ptr
+= strlen(ptr
) + 1;
1186 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1187 ptr
+= strlen(ptr
) + 1;
1188 strcpy(ptr
, "FOO=BAR");
1189 ptr
+= strlen(ptr
) + 1;
1190 strcpy(ptr
, "BAR=FOOBAR");
1191 ptr
+= strlen(ptr
) + 1;
1192 /* copy all existing variables except:
1194 * - PATH (already set above)
1195 * - the directory definitions (=[A-Z]:=)
1197 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1199 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1200 strncmp(ptr2
, "WINELOADER=", 11) != 0 &&
1201 !is_str_env_drive_dir(ptr2
))
1204 ptr
+= strlen(ptr
) + 1;
1208 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1209 /* wait for child to terminate */
1210 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1211 /* child process has changed result file, so let profile functions know about it */
1212 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1214 cmpEnvironment(child_env
);
1216 HeapFree(GetProcessHeap(), 0, child_env
);
1217 FreeEnvironmentStringsA(env
);
1219 assert(DeleteFileA(resfile
) != 0);
1222 static void test_SuspendFlag(void)
1224 char buffer
[MAX_PATH
];
1225 PROCESS_INFORMATION info
;
1226 STARTUPINFOA startup
, us
;
1230 /* let's start simplistic */
1231 memset(&startup
, 0, sizeof(startup
));
1232 startup
.cb
= sizeof(startup
);
1233 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1234 startup
.wShowWindow
= SW_SHOWNORMAL
;
1236 get_file_name(resfile
);
1237 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1238 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1240 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1242 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1243 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1245 /* wait for child to terminate */
1246 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1247 /* child process has changed result file, so let profile functions know about it */
1248 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1250 GetStartupInfoA(&us
);
1252 okChildInt("StartupInfoA", "cb", startup
.cb
);
1253 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1254 result
= getChildString( "StartupInfoA", "lpTitle" );
1255 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1256 "expected '%s' or null, got '%s'\n", selfname
, result
);
1257 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1258 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1259 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1260 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1261 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1262 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1263 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1264 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1265 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1267 assert(DeleteFileA(resfile
) != 0);
1270 static void test_DebuggingFlag(void)
1272 char buffer
[MAX_PATH
];
1273 void *processbase
= NULL
;
1274 PROCESS_INFORMATION info
;
1275 STARTUPINFOA startup
, us
;
1280 /* let's start simplistic */
1281 memset(&startup
, 0, sizeof(startup
));
1282 startup
.cb
= sizeof(startup
);
1283 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1284 startup
.wShowWindow
= SW_SHOWNORMAL
;
1286 get_file_name(resfile
);
1287 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1288 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1290 /* get all startup events up to the entry point break exception */
1293 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1294 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1297 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1298 "first event: %d\n", de
.dwDebugEventCode
);
1299 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1301 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1302 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1303 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1304 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1306 ok(dbg
, "I have seen a debug event\n");
1307 /* wait for child to terminate */
1308 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1309 /* child process has changed result file, so let profile functions know about it */
1310 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1312 GetStartupInfoA(&us
);
1314 okChildInt("StartupInfoA", "cb", startup
.cb
);
1315 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1316 result
= getChildString( "StartupInfoA", "lpTitle" );
1317 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1318 "expected '%s' or null, got '%s'\n", selfname
, result
);
1319 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1320 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1321 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1322 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1323 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1324 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1325 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1326 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1327 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1329 assert(DeleteFileA(resfile
) != 0);
1332 static BOOL
is_console(HANDLE h
)
1334 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1337 static void test_Console(void)
1339 char buffer
[MAX_PATH
];
1340 PROCESS_INFORMATION info
;
1341 STARTUPINFOA startup
, us
;
1342 SECURITY_ATTRIBUTES sa
;
1343 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1344 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1345 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1347 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1348 const char* msg
= "This is a std-handle inheritance test.";
1350 BOOL run_tests
= TRUE
;
1353 memset(&startup
, 0, sizeof(startup
));
1354 startup
.cb
= sizeof(startup
);
1355 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1356 startup
.wShowWindow
= SW_SHOWNORMAL
;
1358 sa
.nLength
= sizeof(sa
);
1359 sa
.lpSecurityDescriptor
= NULL
;
1360 sa
.bInheritHandle
= TRUE
;
1362 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1363 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1365 /* first, we need to be sure we're attached to a console */
1366 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1368 /* we're not attached to a console, let's do it */
1370 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1371 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1373 /* now verify everything's ok */
1374 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1375 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1376 startup
.hStdError
= startup
.hStdOutput
;
1378 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1379 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
) &&
1380 GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console modes\n");
1381 cpIn
= GetConsoleCP();
1382 cpOut
= GetConsoleOutputCP();
1384 get_file_name(resfile
);
1385 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" console", selfname
, resfile
);
1386 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1388 /* wait for child to terminate */
1389 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1390 /* child process has changed result file, so let profile functions know about it */
1391 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1393 /* now get the modification the child has made, and resets parents expected values */
1394 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1395 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
) &&
1396 GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console modes\n");
1398 SetConsoleMode(startup
.hStdInput
, modeIn
);
1399 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1401 cpInC
= GetConsoleCP();
1402 cpOutC
= GetConsoleOutputCP();
1404 /* Try to set invalid CP */
1405 SetLastError(0xdeadbeef);
1406 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1407 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1408 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1409 "GetLastError: expecting %u got %u\n",
1410 ERROR_INVALID_PARAMETER
, GetLastError());
1411 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1415 SetLastError(0xdeadbeef);
1416 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1417 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1418 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1419 "GetLastError: expecting %u got %u\n",
1420 ERROR_INVALID_PARAMETER
, GetLastError());
1423 SetConsoleOutputCP(cpOut
);
1425 GetStartupInfoA(&us
);
1427 okChildInt("StartupInfoA", "cb", startup
.cb
);
1428 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1429 result
= getChildString( "StartupInfoA", "lpTitle" );
1430 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1431 "expected '%s' or null, got '%s'\n", selfname
, result
);
1432 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1433 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1434 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1435 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1436 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1437 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1438 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1439 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1440 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1442 /* check child correctly inherited the console */
1443 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1444 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1445 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1446 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1447 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1448 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1449 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1450 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1451 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1452 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1453 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1454 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1455 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1456 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1457 okChildInt("Console", "InputCP", cpIn
);
1458 okChildInt("Console", "OutputCP", cpOut
);
1459 okChildInt("Console", "InputMode", modeIn
);
1460 okChildInt("Console", "OutputMode", modeOut
);
1464 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1465 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1468 win_skip("Setting the codepage is not implemented\n");
1470 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1471 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1472 trace("cursor position(X): %d/%d\n",sbi
.dwCursorPosition
.X
, sbiC
.dwCursorPosition
.X
);
1473 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1476 assert(DeleteFileA(resfile
) != 0);
1478 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1479 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1480 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1481 "Duplicating as inheritable child-output pipe\n");
1482 CloseHandle(hChildOut
);
1484 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1485 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1486 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1487 "Duplicating as inheritable child-input pipe\n");
1488 CloseHandle(hChildIn
);
1490 memset(&startup
, 0, sizeof(startup
));
1491 startup
.cb
= sizeof(startup
);
1492 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1493 startup
.wShowWindow
= SW_SHOWNORMAL
;
1494 startup
.hStdInput
= hChildInInh
;
1495 startup
.hStdOutput
= hChildOutInh
;
1496 startup
.hStdError
= hChildOutInh
;
1498 get_file_name(resfile
);
1499 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname
, resfile
);
1500 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1501 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1502 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1504 msg_len
= strlen(msg
) + 1;
1505 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1506 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1507 memset(buffer
, 0, sizeof(buffer
));
1508 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1509 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1511 /* wait for child to terminate */
1512 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1513 /* child process has changed result file, so let profile functions know about it */
1514 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1516 okChildString("StdHandle", "msg", msg
);
1519 assert(DeleteFileA(resfile
) != 0);
1522 static void test_ExitCode(void)
1524 char buffer
[MAX_PATH
];
1525 PROCESS_INFORMATION info
;
1526 STARTUPINFOA startup
;
1529 /* let's start simplistic */
1530 memset(&startup
, 0, sizeof(startup
));
1531 startup
.cb
= sizeof(startup
);
1532 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1533 startup
.wShowWindow
= SW_SHOWNORMAL
;
1535 get_file_name(resfile
);
1536 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname
, resfile
);
1537 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1539 /* wait for child to terminate */
1540 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1541 /* child process has changed result file, so let profile functions know about it */
1542 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1544 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1545 okChildInt("ExitCode", "value", code
);
1548 assert(DeleteFileA(resfile
) != 0);
1551 static void test_OpenProcess(void)
1555 MEMORY_BASIC_INFORMATION info
;
1556 SIZE_T dummy
, read_bytes
;
1559 /* not exported in all windows versions */
1560 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1561 win_skip("VirtualAllocEx not found\n");
1565 /* without PROCESS_VM_OPERATION */
1566 hproc
= OpenProcess(PROCESS_ALL_ACCESS_NT4
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1567 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1569 SetLastError(0xdeadbeef);
1570 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1571 ok(!addr1
, "VirtualAllocEx should fail\n");
1572 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1575 win_skip("VirtualAllocEx not implemented\n");
1578 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1580 read_bytes
= 0xdeadbeef;
1581 SetLastError(0xdeadbeef);
1582 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1583 ok(ret
, "ReadProcessMemory error %d\n", GetLastError());
1584 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1588 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1589 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1591 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1592 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1594 /* without PROCESS_QUERY_INFORMATION */
1595 SetLastError(0xdeadbeef);
1596 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1597 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1598 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1600 /* without PROCESS_VM_READ */
1601 read_bytes
= 0xdeadbeef;
1602 SetLastError(0xdeadbeef);
1603 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1604 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1605 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1606 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1610 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1612 memset(&info
, 0xcc, sizeof(info
));
1613 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1614 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1616 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1617 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1618 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1619 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1620 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1621 /* NT reports Protect == 0 for a not committed memory block */
1622 ok(info
.Protect
== 0 /* NT */ ||
1623 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1624 "%x != PAGE_NOACCESS\n", info
.Protect
);
1625 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1627 SetLastError(0xdeadbeef);
1628 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1629 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1630 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1634 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
1637 SetLastError(0xdeadbeef);
1638 memset(&info
, 0xcc, sizeof(info
));
1639 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1640 if (read_bytes
) /* win8 */
1642 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1643 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1644 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1645 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1646 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1647 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1648 ok(info
.Protect
== 0, "%x != PAGE_NOACCESS\n", info
.Protect
);
1649 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1651 else /* before win8 */
1652 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1654 SetLastError(0xdeadbeef);
1655 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1656 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1657 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1662 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1665 static void test_GetProcessVersion(void)
1667 static char cmdline
[] = "winver.exe";
1668 PROCESS_INFORMATION pi
;
1672 SetLastError(0xdeadbeef);
1673 ret
= GetProcessVersion(0);
1674 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1676 SetLastError(0xdeadbeef);
1677 ret
= GetProcessVersion(GetCurrentProcessId());
1678 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1680 memset(&si
, 0, sizeof(si
));
1682 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1683 si
.wShowWindow
= SW_HIDE
;
1684 SetLastError(0xdeadbeef);
1685 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1686 ok(ret
, "CreateProcess error %u\n", GetLastError());
1688 SetLastError(0xdeadbeef);
1689 ret
= GetProcessVersion(pi
.dwProcessId
);
1690 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1692 SetLastError(0xdeadbeef);
1693 ret
= TerminateProcess(pi
.hProcess
, 0);
1694 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1696 CloseHandle(pi
.hProcess
);
1697 CloseHandle(pi
.hThread
);
1700 static void test_GetProcessImageFileNameA(void)
1703 CHAR process
[MAX_PATH
];
1704 static const char harddisk
[] = "\\Device\\HarddiskVolume";
1706 if (!pK32GetProcessImageFileNameA
)
1708 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1712 /* callers must guess the buffer size */
1713 SetLastError(0xdeadbeef);
1714 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL
, 0);
1715 ok(!rc
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
1716 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc
, GetLastError());
1719 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), process
, sizeof(process
));
1720 expect_eq_d(rc
, lstrlenA(process
));
1721 if (strncmp(process
, harddisk
, lstrlenA(harddisk
)))
1723 todo_wine
win_skip("%s is probably on a network share, skipping tests\n", process
);
1727 if (!pQueryFullProcessImageNameA
)
1728 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1731 CHAR image
[MAX_PATH
];
1734 length
= sizeof(image
);
1735 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE
, image
, &length
));
1736 expect_eq_d(length
, lstrlenA(image
));
1737 ok(lstrcmpiA(process
, image
) == 0, "expected '%s' to be equal to '%s'\n", process
, image
);
1741 static void test_QueryFullProcessImageNameA(void)
1743 #define INIT_STR "Just some words"
1745 CHAR buf
[MAX_PATH
], module
[MAX_PATH
];
1747 if (!pQueryFullProcessImageNameA
)
1749 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1754 SetLastError(0); /* old Windows don't reset it on success */
1755 size
= GetModuleFileNameA(NULL
, module
, sizeof(module
));
1756 ok(size
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
, "GetModuleFileName failed: %u le=%u\n", size
, GetLastError());
1758 /* get the buffer length without \0 terminator */
1759 length
= sizeof(buf
);
1760 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1761 expect_eq_d(length
, lstrlenA(buf
));
1762 ok((buf
[0] == '\\' && buf
[1] == '\\') ||
1763 lstrcmpiA(buf
, module
) == 0, "expected %s to match %s\n", buf
, module
);
1765 /* when the buffer is too small
1766 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1767 * - the size variable is not modified
1768 * tested with the biggest too small size
1771 sprintf(buf
,INIT_STR
);
1772 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1773 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1774 expect_eq_d(length
, size
);
1775 expect_eq_s(INIT_STR
, buf
);
1777 /* retest with smaller buffer size
1780 sprintf(buf
,INIT_STR
);
1781 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1782 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1783 expect_eq_d(4, size
);
1784 expect_eq_s(INIT_STR
, buf
);
1786 /* this is a difference between the ascii and the unicode version
1787 * the unicode version crashes when the size is big enough to hold
1788 * the result while the ascii version throws an error
1791 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1792 expect_eq_d(1024, size
);
1793 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1796 static void test_QueryFullProcessImageNameW(void)
1799 WCHAR module_name
[1024], device
[1024];
1800 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
1804 if (!pQueryFullProcessImageNameW
)
1806 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1810 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1812 /* GetCurrentProcess pseudo-handle */
1813 size
= sizeof(buf
) / sizeof(buf
[0]);
1814 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
1815 expect_eq_d(lstrlenW(buf
), size
);
1816 expect_eq_ws_i(buf
, module_name
);
1818 hSelf
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1820 size
= sizeof(buf
) / sizeof(buf
[0]);
1821 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1822 expect_eq_d(lstrlenW(buf
), size
);
1823 expect_eq_ws_i(buf
, module_name
);
1825 /* Buffer too small */
1826 size
= lstrlenW(module_name
)/2;
1827 lstrcpyW(buf
, deviceW
);
1828 SetLastError(0xdeadbeef);
1829 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1830 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1831 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1832 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
1834 /* Too small - not space for NUL terminator */
1835 size
= lstrlenW(module_name
);
1836 SetLastError(0xdeadbeef);
1837 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1838 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
1839 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1843 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
1844 expect_eq_d(0, size
);
1845 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1847 /* Buffer too small */
1848 size
= lstrlenW(module_name
)/2;
1849 SetLastError(0xdeadbeef);
1850 lstrcpyW(buf
, module_name
);
1851 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1852 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1853 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1854 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
1858 size
= sizeof(buf
) / sizeof(buf
[0]);
1859 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
1860 expect_eq_d(lstrlenW(buf
), size
);
1861 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
1862 ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
1864 module_name
[2] = '\0';
1866 size
= QueryDosDeviceW(module_name
, device
, sizeof(device
)/sizeof(device
[0]));
1867 ok(size
, "QueryDosDeviceW failed: le=%u\n", GetLastError());
1868 len
= lstrlenW(device
);
1869 ok(size
>= len
+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size
, len
, wine_dbgstr_w(device
));
1871 if (size
>= lstrlenW(buf
))
1873 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
1877 ok(buf
[len
] == '\\', "expected '%c' to be a '\\' in %s\n", buf
[len
], wine_dbgstr_w(module_name
));
1879 ok(lstrcmpiW(device
, buf
) == 0, "expected %s to match %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
1880 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));
1886 static void test_Handles(void)
1888 HANDLE handle
= GetCurrentProcess();
1893 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
1894 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
1895 "invalid current process handle %p\n", handle
);
1896 ret
= GetExitCodeProcess( handle
, &code
);
1897 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1899 /* truncated handle */
1900 SetLastError( 0xdeadbeef );
1901 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
1902 ret
= GetExitCodeProcess( handle
, &code
);
1903 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1904 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1905 /* sign-extended handle */
1906 SetLastError( 0xdeadbeef );
1907 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
1908 ret
= GetExitCodeProcess( handle
, &code
);
1909 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1910 /* invalid high-word */
1911 SetLastError( 0xdeadbeef );
1912 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
1913 ret
= GetExitCodeProcess( handle
, &code
);
1914 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1915 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1918 handle
= GetStdHandle( STD_ERROR_HANDLE
);
1919 ok( handle
!= 0, "handle %p\n", handle
);
1920 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
1921 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1922 SetStdHandle( STD_ERROR_HANDLE
, h3
);
1923 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
1924 h2
= GetStdHandle( STD_ERROR_HANDLE
);
1926 broken( h2
== h3
) || /* nt4, w2k */
1927 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
1928 "wrong handle %p/%p\n", h2
, h3
);
1929 SetStdHandle( STD_ERROR_HANDLE
, handle
);
1932 static void test_IsWow64Process(void)
1934 PROCESS_INFORMATION pi
;
1938 static char cmdline
[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
1939 static char cmdline_wow64
[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
1941 if (!pIsWow64Process
)
1943 skip("IsWow64Process is not available\n");
1947 memset(&si
, 0, sizeof(si
));
1949 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1950 si
.wShowWindow
= SW_HIDE
;
1951 ret
= CreateProcessA(NULL
, cmdline_wow64
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1954 trace("Created process %s\n", cmdline_wow64
);
1956 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
1957 ok(ret
, "IsWow64Process failed.\n");
1958 ok(is_wow64
, "is_wow64 returned FALSE.\n");
1960 ret
= TerminateProcess(pi
.hProcess
, 0);
1961 ok(ret
, "TerminateProcess error\n");
1963 CloseHandle(pi
.hProcess
);
1964 CloseHandle(pi
.hThread
);
1967 memset(&si
, 0, sizeof(si
));
1969 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1970 si
.wShowWindow
= SW_HIDE
;
1971 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1974 trace("Created process %s\n", cmdline
);
1976 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
1977 ok(ret
, "IsWow64Process failed.\n");
1978 ok(!is_wow64
, "is_wow64 returned TRUE.\n");
1980 ret
= TerminateProcess(pi
.hProcess
, 0);
1981 ok(ret
, "TerminateProcess error\n");
1983 CloseHandle(pi
.hProcess
);
1984 CloseHandle(pi
.hThread
);
1988 static void test_SystemInfo(void)
1990 SYSTEM_INFO si
, nsi
;
1993 if (!pGetNativeSystemInfo
)
1995 win_skip("GetNativeSystemInfo is not available\n");
1999 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
2002 pGetNativeSystemInfo(&nsi
);
2005 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
2007 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
2008 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2009 S(U(nsi
)).wProcessorArchitecture
);
2010 ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
,
2011 "Expected PROCESSOR_AMD_X8664, got %d\n",
2012 nsi
.dwProcessorType
);
2017 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
2018 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2019 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
2020 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
2021 "Expected no difference for dwProcessorType, got %d and %d\n",
2022 si
.dwProcessorType
, nsi
.dwProcessorType
);
2026 static void test_RegistryQuota(void)
2029 DWORD max_quota
, used_quota
;
2031 if (!pGetSystemRegistryQuota
)
2033 win_skip("GetSystemRegistryQuota is not available\n");
2037 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
2039 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2041 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
2043 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2045 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
2047 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2049 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
2051 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2054 static void test_TerminateProcess(void)
2056 static char cmdline
[] = "winver.exe";
2057 PROCESS_INFORMATION pi
;
2060 HANDLE dummy
, thread
;
2062 memset(&si
, 0, sizeof(si
));
2064 SetLastError(0xdeadbeef);
2065 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2066 ok(ret
, "CreateProcess error %u\n", GetLastError());
2068 SetLastError(0xdeadbeef);
2069 thread
= CreateRemoteThread(pi
.hProcess
, NULL
, 0, (void *)0xdeadbeef, NULL
, CREATE_SUSPENDED
, &ret
);
2070 ok(thread
!= 0, "CreateRemoteThread error %d\n", GetLastError());
2072 /* create a not closed thread handle duplicate in the target process */
2073 SetLastError(0xdeadbeef);
2074 ret
= DuplicateHandle(GetCurrentProcess(), thread
, pi
.hProcess
, &dummy
,
2075 0, FALSE
, DUPLICATE_SAME_ACCESS
);
2076 ok(ret
, "DuplicateHandle error %u\n", GetLastError());
2078 SetLastError(0xdeadbeef);
2079 ret
= TerminateThread(thread
, 0);
2080 ok(ret
, "TerminateThread error %u\n", GetLastError());
2081 CloseHandle(thread
);
2083 SetLastError(0xdeadbeef);
2084 ret
= TerminateProcess(pi
.hProcess
, 0);
2085 ok(ret
, "TerminateProcess error %u\n", GetLastError());
2087 CloseHandle(pi
.hProcess
);
2088 CloseHandle(pi
.hThread
);
2091 static void test_DuplicateHandle(void)
2093 char path
[MAX_PATH
], file_name
[MAX_PATH
];
2094 HANDLE f
, fmin
, out
;
2098 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2099 GetCurrentProcess(), &out
, 0, FALSE
,
2100 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2101 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2102 r
= GetHandleInformation(out
, &info
);
2103 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2104 ok(info
== 0, "info = %x\n", info
);
2105 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2108 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2109 GetCurrentProcess(), &out
, 0, TRUE
,
2110 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2111 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2112 r
= GetHandleInformation(out
, &info
);
2113 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2114 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2115 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2118 GetTempPathA(MAX_PATH
, path
);
2119 GetTempFileNameA(path
, "wt", 0, file_name
);
2120 f
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
2121 if (f
== INVALID_HANDLE_VALUE
)
2123 ok(0, "could not create %s\n", file_name
);
2127 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2128 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2129 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2130 ok(f
== out
, "f != out\n");
2131 r
= GetHandleInformation(out
, &info
);
2132 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2133 ok(info
== 0, "info = %x\n", info
);
2135 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2136 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2137 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2138 ok(f
== out
, "f != out\n");
2139 r
= GetHandleInformation(out
, &info
);
2140 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2141 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2143 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, HANDLE_FLAG_PROTECT_FROM_CLOSE
);
2144 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2145 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2146 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2147 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2148 ok(f
!= out
, "f == out\n");
2149 r
= GetHandleInformation(out
, &info
);
2150 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2151 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2152 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, 0);
2153 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2155 /* Test if DuplicateHandle allocates first free handle */
2166 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2167 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2168 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2169 ok(f
== out
, "f != out\n");
2171 DeleteFileA(file_name
);
2173 f
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2176 skip("DuplicateHandle on console handle\n");
2181 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2182 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2183 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2184 todo_wine
ok(f
!= out
, "f == out\n");
2188 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2189 static void _test_completion(int line
, HANDLE port
, DWORD ekey
, ULONG_PTR evalue
, ULONG_PTR eoverlapped
, DWORD wait
)
2191 LPOVERLAPPED overlapped
;
2196 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, wait
);
2198 ok_(__FILE__
, line
)(ret
, "GetQueuedCompletionStatus: %x\n", GetLastError());
2201 ok_(__FILE__
, line
)(key
== ekey
, "unexpected key %x\n", key
);
2202 ok_(__FILE__
, line
)(value
== evalue
, "unexpected value %p\n", (void *)value
);
2203 ok_(__FILE__
, line
)(overlapped
== (LPOVERLAPPED
)eoverlapped
, "unexpected overlapped %p\n", overlapped
);
2207 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2208 static void _create_process(int line
, const char *command
, LPPROCESS_INFORMATION pi
)
2211 char buffer
[MAX_PATH
];
2212 STARTUPINFOA si
= {0};
2214 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, command
);
2216 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, pi
);
2217 ok_(__FILE__
, line
)(ret
, "CreateProcess error %u\n", GetLastError());
2221 static void test_IsProcessInJob(void)
2224 PROCESS_INFORMATION pi
;
2228 if (!pIsProcessInJob
)
2230 win_skip("IsProcessInJob not available.\n");
2234 job
= pCreateJobObjectW(NULL
, NULL
);
2235 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2237 job2
= pCreateJobObjectW(NULL
, NULL
);
2238 ok(job2
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2240 create_process("wait", &pi
);
2243 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2244 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2245 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2248 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2249 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2250 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2253 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2254 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2255 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2257 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2258 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2261 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2262 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2263 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2266 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2267 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2268 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2271 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2272 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2273 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2275 TerminateProcess(pi
.hProcess
, 0);
2277 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2278 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2281 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2282 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2283 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2285 CloseHandle(pi
.hProcess
);
2286 CloseHandle(pi
.hThread
);
2291 static void test_TerminateJobObject(void)
2294 PROCESS_INFORMATION pi
;
2298 job
= pCreateJobObjectW(NULL
, NULL
);
2299 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2301 create_process("wait", &pi
);
2303 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2304 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2306 ret
= pTerminateJobObject(job
, 123);
2307 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2309 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2310 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2311 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2313 ret
= GetExitCodeProcess(pi
.hProcess
, &dwret
);
2314 ok(ret
, "GetExitCodeProcess error %u\n", GetLastError());
2315 ok(dwret
== 123 || broken(dwret
== 0) /* randomly fails on Win 2000 / XP */,
2316 "wrong exitcode %u\n", dwret
);
2318 CloseHandle(pi
.hProcess
);
2319 CloseHandle(pi
.hThread
);
2321 /* Test adding an already terminated process to a job object */
2322 create_process("exit", &pi
);
2324 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2325 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2327 SetLastError(0xdeadbeef);
2328 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2329 ok(!ret
, "AssignProcessToJobObject unexpectedly succeeded\n");
2330 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2332 CloseHandle(pi
.hProcess
);
2333 CloseHandle(pi
.hThread
);
2338 static void test_QueryInformationJobObject(void)
2340 char buf
[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST
) + sizeof(ULONG_PTR
) * 4];
2341 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2342 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info
;
2343 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit_info
= &ext_limit_info
.BasicLimitInformation
;
2344 DWORD dwret
, ret_len
;
2345 PROCESS_INFORMATION pi
[2];
2349 job
= pCreateJobObjectW(NULL
, NULL
);
2350 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2352 /* Only active processes are returned */
2353 create_process("exit", &pi
[0]);
2354 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2355 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2356 dwret
= WaitForSingleObject(pi
[0].hProcess
, 1000);
2357 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2359 CloseHandle(pi
[0].hProcess
);
2360 CloseHandle(pi
[0].hThread
);
2362 create_process("wait", &pi
[0]);
2363 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2364 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2366 create_process("wait", &pi
[1]);
2367 ret
= pAssignProcessToJobObject(job
, pi
[1].hProcess
);
2368 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2370 SetLastError(0xdeadbeef);
2371 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2372 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
), &ret_len
);
2373 ok(!ret
, "QueryInformationJobObject expected failure\n");
2375 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2377 SetLastError(0xdeadbeef);
2378 memset(buf
, 0, sizeof(buf
));
2379 pid_list
->NumberOfAssignedProcesses
= 42;
2380 pid_list
->NumberOfProcessIdsInList
= 42;
2381 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2382 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[1]), &ret_len
);
2383 ok(!ret
, "QueryInformationJobObject expected failure\n");
2385 expect_eq_d(ERROR_MORE_DATA
, GetLastError());
2388 expect_eq_d(42, pid_list
->NumberOfAssignedProcesses
);
2389 expect_eq_d(42, pid_list
->NumberOfProcessIdsInList
);
2392 memset(buf
, 0, sizeof(buf
));
2393 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2395 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2398 if (pid_list
->NumberOfAssignedProcesses
== 3) /* Win 8 */
2399 win_skip("Number of assigned processes broken on Win 8\n");
2402 ULONG_PTR
*list
= pid_list
->ProcessIdList
;
2404 ok(ret_len
== FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[2]),
2405 "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2407 expect_eq_d(2, pid_list
->NumberOfAssignedProcesses
);
2408 expect_eq_d(2, pid_list
->NumberOfProcessIdsInList
);
2409 expect_eq_d(pi
[0].dwProcessId
, list
[0]);
2410 expect_eq_d(pi
[1].dwProcessId
, list
[1]);
2414 /* test JobObjectBasicLimitInformation */
2415 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2416 sizeof(*basic_limit_info
) - 1, &ret_len
);
2417 ok(!ret
, "QueryInformationJobObject expected failure\n");
2418 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2420 ret_len
= 0xdeadbeef;
2421 memset(basic_limit_info
, 0x11, sizeof(*basic_limit_info
));
2422 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2423 sizeof(*basic_limit_info
), &ret_len
);
2424 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2425 ok(ret_len
== sizeof(*basic_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2426 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2428 /* test JobObjectExtendedLimitInformation */
2429 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2430 sizeof(ext_limit_info
) - 1, &ret_len
);
2431 ok(!ret
, "QueryInformationJobObject expected failure\n");
2432 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2434 ret_len
= 0xdeadbeef;
2435 memset(&ext_limit_info
, 0x11, sizeof(ext_limit_info
));
2436 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2437 sizeof(ext_limit_info
), &ret_len
);
2438 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2439 ok(ret_len
== sizeof(ext_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2440 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2442 TerminateProcess(pi
[0].hProcess
, 0);
2443 CloseHandle(pi
[0].hProcess
);
2444 CloseHandle(pi
[0].hThread
);
2446 TerminateProcess(pi
[1].hProcess
, 0);
2447 CloseHandle(pi
[1].hProcess
);
2448 CloseHandle(pi
[1].hThread
);
2453 static void test_CompletionPort(void)
2455 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
2456 PROCESS_INFORMATION pi
;
2461 job
= pCreateJobObjectW(NULL
, NULL
);
2462 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2464 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
2465 ok(port
!= NULL
, "CreateIoCompletionPort error %u\n", GetLastError());
2467 port_info
.CompletionKey
= job
;
2468 port_info
.CompletionPort
= port
;
2469 ret
= pSetInformationJobObject(job
, JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
2470 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2472 create_process("wait", &pi
);
2474 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2475 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2477 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2479 TerminateProcess(pi
.hProcess
, 0);
2480 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2481 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2483 test_completion(port
, JOB_OBJECT_MSG_EXIT_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2484 test_completion(port
, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
, (DWORD_PTR
)job
, 0, 100);
2486 CloseHandle(pi
.hProcess
);
2487 CloseHandle(pi
.hThread
);
2492 static void test_KillOnJobClose(void)
2494 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2495 PROCESS_INFORMATION pi
;
2500 job
= pCreateJobObjectW(NULL
, NULL
);
2501 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2503 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
;
2504 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2505 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
2507 win_skip("Kill on job close limit not available\n");
2510 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2512 create_process("wait", &pi
);
2514 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2515 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2519 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2520 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2521 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2523 CloseHandle(pi
.hProcess
);
2524 CloseHandle(pi
.hThread
);
2527 static void test_WaitForJobObject(void)
2530 PROCESS_INFORMATION pi
;
2534 /* test waiting for a job object when the process is killed */
2535 job
= pCreateJobObjectW(NULL
, NULL
);
2536 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2538 dwret
= WaitForSingleObject(job
, 100);
2539 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2541 create_process("wait", &pi
);
2543 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2544 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2546 dwret
= WaitForSingleObject(job
, 100);
2547 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2549 ret
= pTerminateJobObject(job
, 123);
2550 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2552 dwret
= WaitForSingleObject(job
, 500);
2553 ok(dwret
== WAIT_OBJECT_0
|| broken(dwret
== WAIT_TIMEOUT
),
2554 "WaitForSingleObject returned %u\n", dwret
);
2556 if (dwret
== WAIT_TIMEOUT
) /* Win 2000/XP */
2558 CloseHandle(pi
.hProcess
);
2559 CloseHandle(pi
.hThread
);
2561 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2565 /* the object is not reset immediately */
2566 dwret
= WaitForSingleObject(job
, 100);
2567 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2569 CloseHandle(pi
.hProcess
);
2570 CloseHandle(pi
.hThread
);
2572 /* creating a new process doesn't reset the signalled state */
2573 create_process("wait", &pi
);
2575 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2576 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2578 dwret
= WaitForSingleObject(job
, 100);
2579 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2581 ret
= pTerminateJobObject(job
, 123);
2582 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2584 CloseHandle(pi
.hProcess
);
2585 CloseHandle(pi
.hThread
);
2589 /* repeat the test, but this time the process terminates properly */
2590 job
= pCreateJobObjectW(NULL
, NULL
);
2591 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2593 dwret
= WaitForSingleObject(job
, 100);
2594 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2596 create_process("exit", &pi
);
2598 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2599 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2601 dwret
= WaitForSingleObject(job
, 100);
2602 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2604 CloseHandle(pi
.hProcess
);
2605 CloseHandle(pi
.hThread
);
2609 static HANDLE
test_AddSelfToJob(void)
2614 job
= pCreateJobObjectW(NULL
, NULL
);
2615 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2617 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
2618 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2623 static void test_jobInheritance(HANDLE job
)
2625 char buffer
[MAX_PATH
];
2626 PROCESS_INFORMATION pi
;
2627 STARTUPINFOA si
= {0};
2631 if (!pIsProcessInJob
)
2633 win_skip("IsProcessInJob not available.\n");
2637 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2639 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2640 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2643 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2644 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2645 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2647 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2648 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2650 CloseHandle(pi
.hProcess
);
2651 CloseHandle(pi
.hThread
);
2654 static void test_BreakawayOk(HANDLE job
)
2656 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2657 PROCESS_INFORMATION pi
;
2658 STARTUPINFOA si
= {0};
2659 char buffer
[MAX_PATH
];
2663 if (!pIsProcessInJob
)
2665 win_skip("IsProcessInJob not available.\n");
2669 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2671 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2672 ok(!ret
, "CreateProcessA expected failure\n");
2673 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2677 TerminateProcess(pi
.hProcess
, 0);
2679 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2680 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2682 CloseHandle(pi
.hProcess
);
2683 CloseHandle(pi
.hThread
);
2686 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
2687 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2688 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2690 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2691 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2693 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2694 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2695 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2697 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2698 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2700 CloseHandle(pi
.hProcess
);
2701 CloseHandle(pi
.hThread
);
2703 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
2704 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2705 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2707 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2708 ok(ret
, "CreateProcess error %u\n", GetLastError());
2710 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2711 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2712 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2714 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2715 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2717 CloseHandle(pi
.hProcess
);
2718 CloseHandle(pi
.hThread
);
2720 /* unset breakaway ok */
2721 limit_info
.BasicLimitInformation
.LimitFlags
= 0;
2722 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2723 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2726 static void test_StartupNoConsole(void)
2729 char buffer
[MAX_PATH
];
2730 STARTUPINFOA startup
;
2731 PROCESS_INFORMATION info
;
2736 win_skip( "NtCurrentTeb not supported\n" );
2740 memset(&startup
, 0, sizeof(startup
));
2741 startup
.cb
= sizeof(startup
);
2742 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
2743 startup
.wShowWindow
= SW_SHOWNORMAL
;
2744 get_file_name(resfile
);
2745 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
2746 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
2747 &info
), "CreateProcess\n");
2748 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
2749 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
2750 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
2751 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
2752 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
2753 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
2754 okChildInt("TEB", "hStdInput", 0);
2755 okChildInt("TEB", "hStdOutput", 0);
2756 okChildInt("TEB", "hStdError", 0);
2758 DeleteFileA(resfile
);
2762 static void test_GetNumaProcessorNode(void)
2769 if (!pGetNumaProcessorNode
)
2771 win_skip("GetNumaProcessorNode is missing\n");
2776 for (i
= 0; i
< 256; i
++)
2778 SetLastError(0xdeadbeef);
2779 node
= (i
< si
.dwNumberOfProcessors
) ? 0xFF : 0xAA;
2780 ret
= pGetNumaProcessorNode(i
, &node
);
2781 if (i
< si
.dwNumberOfProcessors
)
2783 ok(ret
, "GetNumaProcessorNode returned FALSE for processor %d\n", i
);
2784 ok(node
!= 0xFF, "expected node != 0xFF, but got 0xFF\n");
2788 ok(!ret
, "GetNumaProcessorNode returned TRUE for processor %d\n", i
);
2789 ok(node
== 0xFF || broken(node
== 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node
);
2790 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2795 static void test_session_info(void)
2797 DWORD session_id
, active_session
;
2800 if (!pProcessIdToSessionId
)
2802 win_skip("ProcessIdToSessionId is missing\n");
2806 r
= pProcessIdToSessionId(GetCurrentProcessId(), &session_id
);
2807 ok(r
, "ProcessIdToSessionId failed: %u\n", GetLastError());
2808 trace("session_id = %x\n", session_id
);
2810 active_session
= pWTSGetActiveConsoleSessionId();
2811 trace("active_session = %x\n", active_session
);
2814 static void test_process_info(void)
2817 static const ULONG info_size
[] =
2819 sizeof(PROCESS_BASIC_INFORMATION
) /* ProcessBasicInformation */,
2820 sizeof(QUOTA_LIMITS
) /* ProcessQuotaLimits */,
2821 sizeof(IO_COUNTERS
) /* ProcessIoCounters */,
2822 sizeof(VM_COUNTERS
) /* ProcessVmCounters */,
2823 sizeof(KERNEL_USER_TIMES
) /* ProcessTimes */,
2824 sizeof(ULONG
) /* ProcessBasePriority */,
2825 sizeof(ULONG
) /* ProcessRaisePriority */,
2826 sizeof(HANDLE
) /* ProcessDebugPort */,
2827 sizeof(HANDLE
) /* ProcessExceptionPort */,
2828 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
2829 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
2830 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
2831 sizeof(ULONG
) /* ProcessDefaultHardErrorMode */,
2832 0 /* ProcessIoPortHandlers: kernel-mode only */,
2833 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
2834 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
2835 sizeof(ULONG
) /* ProcessUserModeIOPL */,
2836 sizeof(BOOLEAN
) /* ProcessEnableAlignmentFaultFixup */,
2837 sizeof(PROCESS_PRIORITY_CLASS
) /* ProcessPriorityClass */,
2838 sizeof(ULONG
) /* ProcessWx86Information */,
2839 sizeof(ULONG
) /* ProcessHandleCount */,
2840 sizeof(ULONG_PTR
) /* ProcessAffinityMask */,
2841 sizeof(ULONG
) /* ProcessPriorityBoost */,
2842 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
2843 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
2844 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
2845 sizeof(ULONG_PTR
) /* ProcessWow64Information */,
2846 sizeof(buf
) /* ProcessImageFileName */,
2847 sizeof(ULONG
) /* ProcessLUIDDeviceMapsEnabled */,
2848 sizeof(ULONG
) /* ProcessBreakOnTermination */,
2849 sizeof(HANDLE
) /* ProcessDebugObjectHandle */,
2850 sizeof(ULONG
) /* ProcessDebugFlags */,
2851 sizeof(buf
) /* ProcessHandleTracing */,
2852 sizeof(ULONG
) /* ProcessIoPriority */,
2853 sizeof(ULONG
) /* ProcessExecuteFlags */,
2854 #if 0 /* FIXME: Add remaning classes */
2855 ProcessResourceManagement
,
2856 sizeof(ULONG
) /* ProcessCookie */,
2857 sizeof(SECTION_IMAGE_INFORMATION
) /* ProcessImageInformation */,
2858 sizeof(PROCESS_CYCLE_TIME_INFORMATION
) /* ProcessCycleTime */,
2859 sizeof(ULONG
) /* ProcessPagePriority */,
2860 40 /* ProcessInstrumentationCallback */,
2861 sizeof(PROCESS_STACK_ALLOCATION_INFORMATION
) /* ProcessThreadStackAllocation */,
2862 sizeof(PROCESS_WS_WATCH_INFORMATION_EX
[]) /* ProcessWorkingSetWatchEx */,
2863 sizeof(buf
) /* ProcessImageFileNameWin32 */,
2864 sizeof(HANDLE
) /* ProcessImageFileMapping */,
2865 sizeof(PROCESS_AFFINITY_UPDATE_MODE
) /* ProcessAffinityUpdateMode */,
2866 sizeof(PROCESS_MEMORY_ALLOCATION_MODE
) /* ProcessMemoryAllocationMode */,
2867 sizeof(USHORT
[]) /* ProcessGroupInformation */,
2868 sizeof(ULONG
) /* ProcessTokenVirtualizationEnabled */,
2869 sizeof(ULONG_PTR
) /* ProcessConsoleHostProcess */,
2870 sizeof(PROCESS_WINDOW_INFORMATION
) /* ProcessWindowInformation */,
2871 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION
) /* ProcessHandleInformation */,
2872 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION
) /* ProcessMitigationPolicy */,
2873 sizeof(ProcessDynamicFunctionTableInformation
) /* ProcessDynamicFunctionTableInformation */,
2874 sizeof(?) /* ProcessHandleCheckingMode */,
2875 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION
) /* ProcessKeepAliveCount */,
2876 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION
) /* ProcessRevokeFileHandles */,
2877 sizeof(PROCESS_WORKING_SET_CONTROL
) /* ProcessWorkingSetControl */,
2878 sizeof(?) /* ProcessHandleTable */,
2879 sizeof(?) /* ProcessCheckStackExtentsMode */,
2880 sizeof(buf
) /* ProcessCommandLineInformation */,
2881 sizeof(PS_PROTECTION
) /* ProcessProtectionInformation */,
2882 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO
) /* ProcessMemoryExhaustion */,
2883 sizeof(PROCESS_FAULT_INFORMATION
) /* ProcessFaultInformation */,
2884 sizeof(PROCESS_TELEMETRY_ID_INFORMATION
) /* ProcessTelemetryIdInformation */,
2885 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION
) /* ProcessCommitReleaseInformation */,
2886 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
2887 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
2888 0 /* ProcessReserved1Information */,
2889 0 /* ProcessReserved2Information */,
2890 sizeof(?) /* ProcessSubsystemProcess */,
2891 sizeof(PROCESS_JOB_MEMORY_INFO
) /* ProcessJobMemoryInformation */,
2895 ULONG i
, status
, ret_len
, size
;
2897 if (!pNtQueryInformationProcess
)
2899 win_skip("NtQueryInformationProcess is not available on this platform\n");
2903 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
2906 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
2910 for (i
= 0; i
< MaxProcessInfoClass
; i
++)
2912 size
= info_size
[i
];
2913 if (!size
) size
= sizeof(buf
);
2915 status
= pNtQueryInformationProcess(hproc
, i
, buf
, info_size
[i
], &ret_len
);
2916 if (status
== STATUS_NOT_IMPLEMENTED
) continue;
2917 if (status
== STATUS_INVALID_INFO_CLASS
) continue;
2918 if (status
== STATUS_INFO_LENGTH_MISMATCH
) continue;
2922 case ProcessBasicInformation
:
2923 case ProcessQuotaLimits
:
2925 case ProcessPriorityClass
:
2926 case ProcessPriorityBoost
:
2927 case ProcessLUIDDeviceMapsEnabled
:
2928 case 33 /* ProcessIoPriority */:
2929 case ProcessIoCounters
:
2930 case ProcessVmCounters
:
2931 case ProcessWow64Information
:
2932 case ProcessDefaultHardErrorMode
:
2933 case ProcessHandleCount
:
2934 ok(status
== STATUS_SUCCESS
, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2937 case ProcessImageFileName
:
2939 ok(status
== STATUS_SUCCESS
, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2942 case ProcessAffinityMask
:
2943 case ProcessBreakOnTermination
:
2944 ok(status
== STATUS_ACCESS_DENIED
/* before win8 */ || status
== STATUS_SUCCESS
/* win8 is less strict */,
2945 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2948 case ProcessDebugObjectHandle
:
2949 ok(status
== STATUS_ACCESS_DENIED
|| status
== STATUS_PORT_NOT_SET
,
2950 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2953 case ProcessExecuteFlags
:
2954 case ProcessDebugPort
:
2955 case ProcessDebugFlags
:
2957 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2961 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2973 ok(b
, "Basic init of CreateProcess test\n");
2978 if (!strcmp(myARGV
[2], "dump") && myARGC
>= 4)
2980 doChild(myARGV
[3], (myARGC
>= 5) ? myARGV
[4] : NULL
);
2983 else if (!strcmp(myARGV
[2], "wait"))
2986 ok(0, "Child process not killed\n");
2989 else if (!strcmp(myARGV
[2], "exit"))
2995 ok(0, "Unexpected command %s\n", myARGV
[2]);
2998 test_process_info();
2999 test_TerminateProcess();
3005 test_DebuggingFlag();
3009 test_GetProcessVersion();
3010 test_GetProcessImageFileNameA();
3011 test_QueryFullProcessImageNameA();
3012 test_QueryFullProcessImageNameW();
3014 test_IsWow64Process();
3016 test_RegistryQuota();
3017 test_DuplicateHandle();
3018 test_StartupNoConsole();
3019 test_GetNumaProcessorNode();
3020 test_session_info();
3022 /* things that can be tested:
3023 * lookup: check the way program to be executed is searched
3024 * handles: check the handle inheritance stuff (+sec options)
3025 * console: check if console creation parameters work
3028 if (!pCreateJobObjectW
)
3030 win_skip("No job object support\n");
3034 test_IsProcessInJob();
3035 test_TerminateJobObject();
3036 test_QueryInformationJobObject();
3037 test_CompletionPort();
3038 test_KillOnJobClose();
3039 test_WaitForJobObject();
3040 job
= test_AddSelfToJob();
3041 test_jobInheritance(job
);
3042 test_BreakawayOk(job
);