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
);
81 /* ############################### */
82 static char base
[MAX_PATH
];
83 static char selfname
[MAX_PATH
];
85 static char resfile
[MAX_PATH
];
90 /* As some environment variables get very long on Unix, we only test for
91 * the first 127 bytes.
92 * Note that increasing this value past 256 may exceed the buffer size
93 * limitations of the *Profile functions (at least on Wine).
95 #define MAX_LISTED_ENV_VAR 128
97 /* ---------------- portable memory allocation thingie */
99 static char memory
[1024*256];
100 static char* memory_index
= memory
;
102 static char* grab_memory(size_t len
)
104 char* ret
= memory_index
;
106 len
= (len
+ 3) & ~3;
108 assert(memory_index
<= memory
+ sizeof(memory
));
112 static void release_memory(void)
114 memory_index
= memory
;
117 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
119 static const char* encodeA(const char* str
)
125 len
= strlen(str
) + 1;
126 ptr
= grab_memory(len
* 2 + 1);
127 for (i
= 0; i
< len
; i
++)
128 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
133 static const char* encodeW(const WCHAR
* str
)
139 len
= lstrlenW(str
) + 1;
140 ptr
= grab_memory(len
* 4 + 1);
142 for (i
= 0; i
< len
; i
++)
143 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
148 static unsigned decode_char(char c
)
150 if (c
>= '0' && c
<= '9') return c
- '0';
151 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
152 assert(c
>= 'A' && c
<= 'F');
156 static char* decodeA(const char* str
)
161 len
= strlen(str
) / 2;
162 if (!len
--) return NULL
;
163 ptr
= grab_memory(len
+ 1);
164 for (i
= 0; i
< len
; i
++)
165 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
170 /* This will be needed to decode Unicode strings saved by the child process
171 * when we test Unicode functions.
173 static WCHAR
* decodeW(const char* str
)
179 len
= strlen(str
) / 4;
180 if (!len
--) return NULL
;
181 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
182 for (i
= 0; i
< len
; i
++)
183 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
184 (decode_char(str
[4 * i
+ 1]) << 8) |
185 (decode_char(str
[4 * i
+ 2]) << 4) |
186 (decode_char(str
[4 * i
+ 3]) << 0);
191 /******************************************************************
194 * generates basic information like:
195 * base: absolute path to curr dir
196 * selfname: the way to reinvoke ourselves
197 * exename: executable without the path
198 * function-pointers, which are not implemented in all windows versions
200 static BOOL
init(void)
204 myARGC
= winetest_get_mainargs( &myARGV
);
205 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return FALSE
;
206 strcpy(selfname
, myARGV
[0]);
208 /* Strip the path of selfname */
209 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
210 else exename
= selfname
;
212 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
214 hkernel32
= GetModuleHandleA("kernel32");
215 hntdll
= GetModuleHandleA("ntdll.dll");
217 pNtCurrentTeb
= (void *)GetProcAddress(hntdll
, "NtCurrentTeb");
218 pNtQueryInformationProcess
= (void *)GetProcAddress(hntdll
, "NtQueryInformationProcess");
220 pGetNativeSystemInfo
= (void *) GetProcAddress(hkernel32
, "GetNativeSystemInfo");
221 pGetSystemRegistryQuota
= (void *) GetProcAddress(hkernel32
, "GetSystemRegistryQuota");
222 pIsWow64Process
= (void *) GetProcAddress(hkernel32
, "IsWow64Process");
223 pVirtualAllocEx
= (void *) GetProcAddress(hkernel32
, "VirtualAllocEx");
224 pVirtualFreeEx
= (void *) GetProcAddress(hkernel32
, "VirtualFreeEx");
225 pQueryFullProcessImageNameA
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameA");
226 pQueryFullProcessImageNameW
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameW");
227 pK32GetProcessImageFileNameA
= (void *) GetProcAddress(hkernel32
, "K32GetProcessImageFileNameA");
228 pCreateJobObjectW
= (void *)GetProcAddress(hkernel32
, "CreateJobObjectW");
229 pAssignProcessToJobObject
= (void *)GetProcAddress(hkernel32
, "AssignProcessToJobObject");
230 pIsProcessInJob
= (void *)GetProcAddress(hkernel32
, "IsProcessInJob");
231 pTerminateJobObject
= (void *)GetProcAddress(hkernel32
, "TerminateJobObject");
232 pQueryInformationJobObject
= (void *)GetProcAddress(hkernel32
, "QueryInformationJobObject");
233 pSetInformationJobObject
= (void *)GetProcAddress(hkernel32
, "SetInformationJobObject");
234 pCreateIoCompletionPort
= (void *)GetProcAddress(hkernel32
, "CreateIoCompletionPort");
235 pGetNumaProcessorNode
= (void *)GetProcAddress(hkernel32
, "GetNumaProcessorNode");
239 /******************************************************************
242 * generates an absolute file_name for temporary file
245 static void get_file_name(char* buf
)
250 GetTempPathA(sizeof(path
), path
);
251 GetTempFileNameA(path
, "wt", 0, buf
);
254 /******************************************************************
255 * static void childPrintf
258 static void childPrintf(HANDLE h
, const char* fmt
, ...)
261 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
264 va_start(valist
, fmt
);
265 vsprintf(buffer
, fmt
, valist
);
267 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
271 /******************************************************************
274 * output most of the information in the child process
276 static void doChild(const char* file
, const char* option
)
281 char *ptrA
, *ptrA_save
;
282 WCHAR
*ptrW
, *ptrW_save
;
284 WCHAR bufW
[MAX_PATH
];
285 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
288 if (hFile
== INVALID_HANDLE_VALUE
) return;
290 /* output of startup info (Ansi) */
291 GetStartupInfoA(&siA
);
293 "[StartupInfoA]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
294 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
295 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
296 "dwFlags=%lu\nwShowWindow=%u\n"
297 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
298 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
299 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
300 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
301 siA
.dwFlags
, siA
.wShowWindow
,
302 (DWORD_PTR
)siA
.hStdInput
, (DWORD_PTR
)siA
.hStdOutput
, (DWORD_PTR
)siA
.hStdError
);
306 RTL_USER_PROCESS_PARAMETERS
*params
= pNtCurrentTeb()->Peb
->ProcessParameters
;
308 /* check the console handles in the TEB */
309 childPrintf(hFile
, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
310 (DWORD_PTR
)params
->hStdInput
, (DWORD_PTR
)params
->hStdOutput
,
311 (DWORD_PTR
)params
->hStdError
);
314 /* since GetStartupInfoW is only implemented in win2k,
315 * zero out before calling so we can notice the difference
317 memset(&siW
, 0, sizeof(siW
));
318 GetStartupInfoW(&siW
);
320 "[StartupInfoW]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
321 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
322 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
323 "dwFlags=%lu\nwShowWindow=%u\n"
324 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
325 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
326 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
327 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
328 siW
.dwFlags
, siW
.wShowWindow
,
329 (DWORD_PTR
)siW
.hStdInput
, (DWORD_PTR
)siW
.hStdOutput
, (DWORD_PTR
)siW
.hStdError
);
332 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
333 for (i
= 0; i
< myARGC
; i
++)
335 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
337 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
338 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
340 /* output of environment (Ansi) */
341 ptrA_save
= ptrA
= GetEnvironmentStringsA();
344 char env_var
[MAX_LISTED_ENV_VAR
];
346 childPrintf(hFile
, "[EnvironmentA]\n");
350 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
351 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
353 ptrA
+= strlen(ptrA
) + 1;
355 childPrintf(hFile
, "len=%d\n\n", i
);
356 FreeEnvironmentStringsA(ptrA_save
);
359 /* output of environment (Unicode) */
360 ptrW_save
= ptrW
= GetEnvironmentStringsW();
363 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
365 childPrintf(hFile
, "[EnvironmentW]\n");
369 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
370 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
371 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
373 ptrW
+= lstrlenW(ptrW
) + 1;
375 childPrintf(hFile
, "len=%d\n\n", i
);
376 FreeEnvironmentStringsW(ptrW_save
);
379 childPrintf(hFile
, "[Misc]\n");
380 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
381 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
382 if (GetCurrentDirectoryW(sizeof(bufW
) / sizeof(bufW
[0]), bufW
))
383 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
384 childPrintf(hFile
, "\n");
386 if (option
&& strcmp(option
, "console") == 0)
388 CONSOLE_SCREEN_BUFFER_INFO sbi
;
389 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
390 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
391 DWORD modeIn
, modeOut
;
393 childPrintf(hFile
, "[Console]\n");
394 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
396 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
397 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
398 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
399 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
400 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
401 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
403 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
404 GetConsoleCP(), GetConsoleOutputCP());
405 if (GetConsoleMode(hConIn
, &modeIn
))
406 childPrintf(hFile
, "InputMode=%ld\n", modeIn
);
407 if (GetConsoleMode(hConOut
, &modeOut
))
408 childPrintf(hFile
, "OutputMode=%ld\n", modeOut
);
410 /* now that we have written all relevant information, let's change it */
411 SetLastError(0xdeadbeef);
412 ret
= SetConsoleCP(1252);
413 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
415 win_skip("Setting the codepage is not implemented\n");
419 ok(ret
, "Setting CP\n");
420 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
423 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
424 ok( ret
, "Setting mode (%d)\n", GetLastError());
425 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
426 ok( ret
, "Setting mode (%d)\n", GetLastError());
427 sbi
.dwCursorPosition
.X
^= 1;
428 sbi
.dwCursorPosition
.Y
^= 1;
429 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
430 ok( ret
, "Setting cursor position (%d)\n", GetLastError());
432 if (option
&& strcmp(option
, "stdhandle") == 0)
434 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
435 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
437 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
442 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
443 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
444 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
448 if (option
&& strcmp(option
, "exit_code") == 0)
450 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
458 static char* getChildString(const char* sect
, const char* key
)
460 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
463 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
464 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
465 assert(!(strlen(buf
) & 1));
470 static WCHAR
* getChildStringW(const char* sect
, const char* key
)
472 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
475 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
476 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
477 assert(!(strlen(buf
) & 1));
482 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
483 * others... (windows uses stricmp while Un*x uses strcasecmp...)
485 static int wtstrcasecmp(const char* p1
, const char* p2
)
490 while (c1
== c2
&& c1
)
492 c1
= *p1
++; c2
= *p2
++;
495 c1
= toupper(c1
); c2
= toupper(c2
);
501 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
503 if (!s1
&& !s2
) return 0;
506 return (sensitive
) ? strcmp(s1
, s2
) : wtstrcasecmp(s1
, s2
);
509 static void ok_child_string( int line
, const char *sect
, const char *key
,
510 const char *expect
, int sensitive
)
512 char* result
= getChildString( sect
, key
);
513 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
514 sect
, key
, expect
? expect
: "(null)", result
);
517 static void ok_child_stringWA( int line
, const char *sect
, const char *key
,
518 const char *expect
, int sensitive
)
523 WCHAR
* result
= getChildStringW( sect
, key
);
525 len
= MultiByteToWideChar( CP_ACP
, 0, expect
, -1, NULL
, 0);
526 expectW
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
527 MultiByteToWideChar( CP_ACP
, 0, expect
, -1, expectW
, len
);
529 len
= WideCharToMultiByte( CP_ACP
, 0, result
, -1, NULL
, 0, NULL
, NULL
);
530 resultA
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(CHAR
));
531 WideCharToMultiByte( CP_ACP
, 0, result
, -1, resultA
, len
, NULL
, NULL
);
534 ok_(__FILE__
, line
)( lstrcmpW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
535 sect
, key
, expect
? expect
: "(null)", resultA
);
537 ok_(__FILE__
, line
)( lstrcmpiW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
538 sect
, key
, expect
? expect
: "(null)", resultA
);
539 HeapFree(GetProcessHeap(),0,expectW
);
540 HeapFree(GetProcessHeap(),0,resultA
);
543 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
544 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
545 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
547 /* using !expect ensures that the test will fail if the sect/key isn't present
550 #define okChildInt(sect, key, expect) \
552 UINT result = GetPrivateProfileIntA((sect), (key), !(expect), resfile); \
553 ok(result == expect, "%s:%s expected %u, but got %u\n", (sect), (key), (UINT)(expect), result); \
556 static void test_Startup(void)
558 char buffer
[MAX_PATH
];
559 PROCESS_INFORMATION info
;
560 STARTUPINFOA startup
,si
;
562 static CHAR title
[] = "I'm the title string",
563 desktop
[] = "winsta0\\default",
566 /* let's start simplistic */
567 memset(&startup
, 0, sizeof(startup
));
568 startup
.cb
= sizeof(startup
);
569 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
570 startup
.wShowWindow
= SW_SHOWNORMAL
;
572 get_file_name(resfile
);
573 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
574 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
575 /* wait for child to terminate */
576 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
577 /* child process has changed result file, so let profile functions know about it */
578 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
580 GetStartupInfoA(&si
);
581 okChildInt("StartupInfoA", "cb", startup
.cb
);
582 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
583 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
584 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
585 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
586 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
587 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
588 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
589 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
590 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
591 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
593 assert(DeleteFileA(resfile
) != 0);
595 /* not so simplistic now */
596 memset(&startup
, 0, sizeof(startup
));
597 startup
.cb
= sizeof(startup
);
598 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
599 startup
.wShowWindow
= SW_SHOWNORMAL
;
600 startup
.lpTitle
= title
;
601 startup
.lpDesktop
= desktop
;
602 startup
.dwXCountChars
= 0x12121212;
603 startup
.dwYCountChars
= 0x23232323;
604 startup
.dwX
= 0x34343434;
605 startup
.dwY
= 0x45454545;
606 startup
.dwXSize
= 0x56565656;
607 startup
.dwYSize
= 0x67676767;
608 startup
.dwFillAttribute
= 0xA55A;
610 get_file_name(resfile
);
611 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
612 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
613 /* wait for child to terminate */
614 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
615 /* child process has changed result file, so let profile functions know about it */
616 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
618 okChildInt("StartupInfoA", "cb", startup
.cb
);
619 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
620 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
621 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
622 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
623 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
624 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
625 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
626 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
627 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
628 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
629 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
631 assert(DeleteFileA(resfile
) != 0);
633 /* not so simplistic now */
634 memset(&startup
, 0, sizeof(startup
));
635 startup
.cb
= sizeof(startup
);
636 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
637 startup
.wShowWindow
= SW_SHOWNORMAL
;
638 startup
.lpTitle
= title
;
639 startup
.lpDesktop
= NULL
;
640 startup
.dwXCountChars
= 0x12121212;
641 startup
.dwYCountChars
= 0x23232323;
642 startup
.dwX
= 0x34343434;
643 startup
.dwY
= 0x45454545;
644 startup
.dwXSize
= 0x56565656;
645 startup
.dwYSize
= 0x67676767;
646 startup
.dwFillAttribute
= 0xA55A;
648 get_file_name(resfile
);
649 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
650 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
651 /* wait for child to terminate */
652 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
653 /* child process has changed result file, so let profile functions know about it */
654 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
656 okChildInt("StartupInfoA", "cb", startup
.cb
);
657 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
658 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
659 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
660 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
661 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
662 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
663 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
664 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
665 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
666 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
667 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
669 assert(DeleteFileA(resfile
) != 0);
671 /* not so simplistic now */
672 memset(&startup
, 0, sizeof(startup
));
673 startup
.cb
= sizeof(startup
);
674 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
675 startup
.wShowWindow
= SW_SHOWNORMAL
;
676 startup
.lpTitle
= title
;
677 startup
.lpDesktop
= empty
;
678 startup
.dwXCountChars
= 0x12121212;
679 startup
.dwYCountChars
= 0x23232323;
680 startup
.dwX
= 0x34343434;
681 startup
.dwY
= 0x45454545;
682 startup
.dwXSize
= 0x56565656;
683 startup
.dwYSize
= 0x67676767;
684 startup
.dwFillAttribute
= 0xA55A;
686 get_file_name(resfile
);
687 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
688 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
689 /* wait for child to terminate */
690 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
691 /* child process has changed result file, so let profile functions know about it */
692 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
694 okChildInt("StartupInfoA", "cb", startup
.cb
);
695 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
696 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
697 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
698 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
699 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
700 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
701 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
702 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
703 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
704 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
705 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
707 assert(DeleteFileA(resfile
) != 0);
709 /* not so simplistic now */
710 memset(&startup
, 0, sizeof(startup
));
711 startup
.cb
= sizeof(startup
);
712 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
713 startup
.wShowWindow
= SW_SHOWNORMAL
;
714 startup
.lpTitle
= NULL
;
715 startup
.lpDesktop
= desktop
;
716 startup
.dwXCountChars
= 0x12121212;
717 startup
.dwYCountChars
= 0x23232323;
718 startup
.dwX
= 0x34343434;
719 startup
.dwY
= 0x45454545;
720 startup
.dwXSize
= 0x56565656;
721 startup
.dwYSize
= 0x67676767;
722 startup
.dwFillAttribute
= 0xA55A;
724 get_file_name(resfile
);
725 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
726 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
727 /* wait for child to terminate */
728 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
729 /* child process has changed result file, so let profile functions know about it */
730 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
732 okChildInt("StartupInfoA", "cb", startup
.cb
);
733 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
734 result
= getChildString( "StartupInfoA", "lpTitle" );
735 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
736 "expected '%s' or null, got '%s'\n", selfname
, result
);
737 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
738 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
739 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
740 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
741 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
742 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
743 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
744 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
745 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
747 assert(DeleteFileA(resfile
) != 0);
749 /* not so simplistic now */
750 memset(&startup
, 0, sizeof(startup
));
751 startup
.cb
= sizeof(startup
);
752 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
753 startup
.wShowWindow
= SW_SHOWNORMAL
;
754 startup
.lpTitle
= empty
;
755 startup
.lpDesktop
= desktop
;
756 startup
.dwXCountChars
= 0x12121212;
757 startup
.dwYCountChars
= 0x23232323;
758 startup
.dwX
= 0x34343434;
759 startup
.dwY
= 0x45454545;
760 startup
.dwXSize
= 0x56565656;
761 startup
.dwYSize
= 0x67676767;
762 startup
.dwFillAttribute
= 0xA55A;
764 get_file_name(resfile
);
765 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
766 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
767 /* wait for child to terminate */
768 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
769 /* child process has changed result file, so let profile functions know about it */
770 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
772 okChildInt("StartupInfoA", "cb", startup
.cb
);
773 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
774 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
775 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
776 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
777 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
778 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
779 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
780 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
781 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
782 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
783 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
785 assert(DeleteFileA(resfile
) != 0);
787 /* not so simplistic now */
788 memset(&startup
, 0, sizeof(startup
));
789 startup
.cb
= sizeof(startup
);
790 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
791 startup
.wShowWindow
= SW_SHOWNORMAL
;
792 startup
.lpTitle
= empty
;
793 startup
.lpDesktop
= empty
;
794 startup
.dwXCountChars
= 0x12121212;
795 startup
.dwYCountChars
= 0x23232323;
796 startup
.dwX
= 0x34343434;
797 startup
.dwY
= 0x45454545;
798 startup
.dwXSize
= 0x56565656;
799 startup
.dwYSize
= 0x67676767;
800 startup
.dwFillAttribute
= 0xA55A;
802 get_file_name(resfile
);
803 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
804 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
805 /* wait for child to terminate */
806 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
807 /* child process has changed result file, so let profile functions know about it */
808 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
810 okChildInt("StartupInfoA", "cb", startup
.cb
);
811 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
812 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
813 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
814 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
815 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
816 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
817 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
818 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
819 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
820 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
821 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
823 assert(DeleteFileA(resfile
) != 0);
825 /* TODO: test for A/W and W/A and W/W */
828 static void test_CommandLine(void)
830 char buffer
[MAX_PATH
], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
831 char buffer2
[MAX_PATH
];
832 PROCESS_INFORMATION info
;
833 STARTUPINFOA startup
;
836 memset(&startup
, 0, sizeof(startup
));
837 startup
.cb
= sizeof(startup
);
838 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
839 startup
.wShowWindow
= SW_SHOWNORMAL
;
842 get_file_name(resfile
);
843 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
844 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
845 /* wait for child to terminate */
846 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
847 /* child process has changed result file, so let profile functions know about it */
848 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
850 okChildInt("Arguments", "argcA", 5);
851 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
852 okChildString("Arguments", "argvA5", NULL
);
853 okChildString("Arguments", "CommandLineA", buffer
);
855 assert(DeleteFileA(resfile
) != 0);
857 memset(&startup
, 0, sizeof(startup
));
858 startup
.cb
= sizeof(startup
);
859 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
860 startup
.wShowWindow
= SW_SHOWNORMAL
;
863 get_file_name(resfile
);
864 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname
, resfile
);
865 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
866 /* wait for child to terminate */
867 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
868 /* child process has changed result file, so let profile functions know about it */
869 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
871 okChildInt("Arguments", "argcA", 7);
872 okChildString("Arguments", "argvA4", "a\"b\\");
873 okChildString("Arguments", "argvA5", "c\"");
874 okChildString("Arguments", "argvA6", "d");
875 okChildString("Arguments", "argvA7", NULL
);
876 okChildString("Arguments", "CommandLineA", buffer
);
878 assert(DeleteFileA(resfile
) != 0);
880 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
881 get_file_name(resfile
);
882 /* Use exename to avoid buffer containing things like 'C:' */
883 sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
884 SetLastError(0xdeadbeef);
885 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
886 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
887 /* wait for child to terminate */
888 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
889 /* child process has changed result file, so let profile functions know about it */
890 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
891 sprintf(buffer
, "./%s", exename
);
892 okChildString("Arguments", "argvA0", buffer
);
894 assert(DeleteFileA(resfile
) != 0);
896 get_file_name(resfile
);
897 /* Use exename to avoid buffer containing things like 'C:' */
898 sprintf(buffer
, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
899 SetLastError(0xdeadbeef);
900 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
901 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
902 /* wait for child to terminate */
903 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
904 /* child process has changed result file, so let profile functions know about it */
905 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
906 sprintf(buffer
, ".\\%s", exename
);
907 okChildString("Arguments", "argvA0", buffer
);
909 assert(DeleteFileA(resfile
) != 0);
911 get_file_name(resfile
);
912 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
913 assert ( lpFilePart
!= 0);
914 *(lpFilePart
-1 ) = 0;
915 p
= strrchr(fullpath
, '\\');
916 /* Use exename to avoid buffer containing things like 'C:' */
917 if (p
) sprintf(buffer
, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p
, exename
, resfile
);
918 else sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
919 SetLastError(0xdeadbeef);
920 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
921 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
922 /* wait for child to terminate */
923 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
924 /* child process has changed result file, so let profile functions know about it */
925 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
926 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
927 else sprintf(buffer
, "./%s", exename
);
928 okChildString("Arguments", "argvA0", buffer
);
930 assert(DeleteFileA(resfile
) != 0);
933 get_file_name(resfile
);
934 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
935 assert ( lpFilePart
!= 0);
936 *(lpFilePart
-1 ) = 0;
937 p
= strrchr(fullpath
, '\\');
938 /* Use exename to avoid buffer containing things like 'C:' */
939 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
940 else sprintf(buffer
, "./%s", exename
);
941 sprintf(buffer2
, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile
);
942 SetLastError(0xdeadbeef);
943 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
944 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
945 /* wait for child to terminate */
946 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
947 /* child process has changed result file, so let profile functions know about it */
948 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
949 sprintf(buffer
, "tests/process.c dump %s", resfile
);
950 okChildString("Arguments", "argvA0", "dummy");
951 okChildString("Arguments", "CommandLineA", buffer2
);
952 okChildStringWA("Arguments", "CommandLineW", buffer2
);
954 assert(DeleteFileA(resfile
) != 0);
956 if (0) /* Test crashes on NT-based Windows. */
958 /* Test NULL application name and command line parameters. */
959 SetLastError(0xdeadbeef);
960 ret
= CreateProcessA(NULL
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
961 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
962 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
963 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
968 /* Test empty application name parameter. */
969 SetLastError(0xdeadbeef);
970 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
971 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
972 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
973 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
974 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
975 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
979 /* Test empty application name and command line parameters. */
980 SetLastError(0xdeadbeef);
981 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
982 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
983 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
984 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
985 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
986 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
988 /* Test empty command line parameter. */
989 SetLastError(0xdeadbeef);
990 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
991 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
992 ok(GetLastError() == ERROR_FILE_NOT_FOUND
||
993 GetLastError() == ERROR_PATH_NOT_FOUND
/* NT4 */ ||
994 GetLastError() == ERROR_BAD_PATHNAME
/* Win98 */ ||
995 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7 */,
996 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
998 strcpy(buffer
, "doesnotexist.exe");
999 strcpy(buffer2
, "does not exist.exe");
1001 /* Test nonexistent application name. */
1002 SetLastError(0xdeadbeef);
1003 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1004 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1005 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1007 SetLastError(0xdeadbeef);
1008 ret
= CreateProcessA(buffer2
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1009 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1010 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1012 /* Test nonexistent command line parameter. */
1013 SetLastError(0xdeadbeef);
1014 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1015 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1016 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1018 SetLastError(0xdeadbeef);
1019 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1020 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1021 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1024 static void test_Directory(void)
1026 char buffer
[MAX_PATH
];
1027 PROCESS_INFORMATION info
;
1028 STARTUPINFOA startup
;
1029 char windir
[MAX_PATH
];
1030 static CHAR cmdline
[] = "winver.exe";
1032 memset(&startup
, 0, sizeof(startup
));
1033 startup
.cb
= sizeof(startup
);
1034 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1035 startup
.wShowWindow
= SW_SHOWNORMAL
;
1038 get_file_name(resfile
);
1039 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1040 GetWindowsDirectoryA( windir
, sizeof(windir
) );
1041 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
1042 /* wait for child to terminate */
1043 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1044 /* child process has changed result file, so let profile functions know about it */
1045 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1047 okChildIString("Misc", "CurrDirA", windir
);
1049 assert(DeleteFileA(resfile
) != 0);
1051 /* search PATH for the exe if directory is NULL */
1052 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1053 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
1055 /* if any directory is provided, don't search PATH, error on bad directory */
1056 SetLastError(0xdeadbeef);
1057 memset(&info
, 0, sizeof(info
));
1058 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
1059 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
1060 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1061 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
1064 static BOOL
is_str_env_drive_dir(const char* str
)
1066 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1067 str
[3] == '=' && str
[4] == str
[1];
1070 /* compared expected child's environment (in gesA) from actual
1071 * environment our child got
1073 static void cmpEnvironment(const char* gesA
)
1081 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1083 /* now look each parent env in child */
1084 if ((ptrA
= gesA
) != NULL
)
1088 for (i
= 0; i
< clen
; i
++)
1090 sprintf(key
, "env%d", i
);
1091 res
= getChildString("EnvironmentA", key
);
1092 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1096 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1098 ptrA
+= strlen(ptrA
) + 1;
1102 /* and each child env in parent */
1103 for (i
= 0; i
< clen
; i
++)
1105 sprintf(key
, "env%d", i
);
1106 res
= getChildString("EnvironmentA", key
);
1107 if ((ptrA
= gesA
) != NULL
)
1111 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1113 ptrA
+= strlen(ptrA
) + 1;
1115 if (!*ptrA
) ptrA
= NULL
;
1118 if (!is_str_env_drive_dir(res
))
1120 found
= ptrA
!= NULL
;
1121 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1123 /* else => should also test we get the right per drive default directory here... */
1127 static void test_Environment(void)
1129 char buffer
[MAX_PATH
];
1130 PROCESS_INFORMATION info
;
1131 STARTUPINFOA startup
;
1139 memset(&startup
, 0, sizeof(startup
));
1140 startup
.cb
= sizeof(startup
);
1141 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1142 startup
.wShowWindow
= SW_SHOWNORMAL
;
1145 get_file_name(resfile
);
1146 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1147 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1148 /* wait for child to terminate */
1149 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1150 /* child process has changed result file, so let profile functions know about it */
1151 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1153 env
= GetEnvironmentStringsA();
1154 cmpEnvironment(env
);
1156 assert(DeleteFileA(resfile
) != 0);
1158 memset(&startup
, 0, sizeof(startup
));
1159 startup
.cb
= sizeof(startup
);
1160 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1161 startup
.wShowWindow
= SW_SHOWNORMAL
;
1164 get_file_name(resfile
);
1165 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1171 slen
= strlen(ptr
)+1;
1172 child_env_len
+= slen
;
1175 /* Add space for additional environment variables */
1176 child_env_len
+= 256;
1177 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1180 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1181 ptr
+= strlen(ptr
) + 1;
1182 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1183 ptr
+= strlen(ptr
) + 1;
1184 strcpy(ptr
, "FOO=BAR");
1185 ptr
+= strlen(ptr
) + 1;
1186 strcpy(ptr
, "BAR=FOOBAR");
1187 ptr
+= strlen(ptr
) + 1;
1188 /* copy all existing variables except:
1190 * - PATH (already set above)
1191 * - the directory definitions (=[A-Z]:=)
1193 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1195 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1196 strncmp(ptr2
, "WINELOADER=", 11) != 0 &&
1197 !is_str_env_drive_dir(ptr2
))
1200 ptr
+= strlen(ptr
) + 1;
1204 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1205 /* wait for child to terminate */
1206 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1207 /* child process has changed result file, so let profile functions know about it */
1208 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1210 cmpEnvironment(child_env
);
1212 HeapFree(GetProcessHeap(), 0, child_env
);
1213 FreeEnvironmentStringsA(env
);
1215 assert(DeleteFileA(resfile
) != 0);
1218 static void test_SuspendFlag(void)
1220 char buffer
[MAX_PATH
];
1221 PROCESS_INFORMATION info
;
1222 STARTUPINFOA startup
, us
;
1226 /* let's start simplistic */
1227 memset(&startup
, 0, sizeof(startup
));
1228 startup
.cb
= sizeof(startup
);
1229 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1230 startup
.wShowWindow
= SW_SHOWNORMAL
;
1232 get_file_name(resfile
);
1233 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1234 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1236 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1238 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1239 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1241 /* wait for child to terminate */
1242 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1243 /* child process has changed result file, so let profile functions know about it */
1244 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1246 GetStartupInfoA(&us
);
1248 okChildInt("StartupInfoA", "cb", startup
.cb
);
1249 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1250 result
= getChildString( "StartupInfoA", "lpTitle" );
1251 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1252 "expected '%s' or null, got '%s'\n", selfname
, result
);
1253 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1254 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1255 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1256 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1257 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1258 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1259 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1260 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1261 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1263 assert(DeleteFileA(resfile
) != 0);
1266 static void test_DebuggingFlag(void)
1268 char buffer
[MAX_PATH
];
1269 void *processbase
= NULL
;
1270 PROCESS_INFORMATION info
;
1271 STARTUPINFOA startup
, us
;
1276 /* let's start simplistic */
1277 memset(&startup
, 0, sizeof(startup
));
1278 startup
.cb
= sizeof(startup
);
1279 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1280 startup
.wShowWindow
= SW_SHOWNORMAL
;
1282 get_file_name(resfile
);
1283 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1284 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1286 /* get all startup events up to the entry point break exception */
1289 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1290 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1293 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1294 "first event: %d\n", de
.dwDebugEventCode
);
1295 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1297 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1298 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1299 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1300 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1302 ok(dbg
, "I have seen a debug event\n");
1303 /* wait for child to terminate */
1304 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1305 /* child process has changed result file, so let profile functions know about it */
1306 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1308 GetStartupInfoA(&us
);
1310 okChildInt("StartupInfoA", "cb", startup
.cb
);
1311 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1312 result
= getChildString( "StartupInfoA", "lpTitle" );
1313 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1314 "expected '%s' or null, got '%s'\n", selfname
, result
);
1315 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1316 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1317 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1318 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1319 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1320 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1321 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1322 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1323 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1325 assert(DeleteFileA(resfile
) != 0);
1328 static BOOL
is_console(HANDLE h
)
1330 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1333 static void test_Console(void)
1335 char buffer
[MAX_PATH
];
1336 PROCESS_INFORMATION info
;
1337 STARTUPINFOA startup
, us
;
1338 SECURITY_ATTRIBUTES sa
;
1339 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1340 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1341 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1343 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1344 const char* msg
= "This is a std-handle inheritance test.";
1346 BOOL run_tests
= TRUE
;
1349 memset(&startup
, 0, sizeof(startup
));
1350 startup
.cb
= sizeof(startup
);
1351 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1352 startup
.wShowWindow
= SW_SHOWNORMAL
;
1354 sa
.nLength
= sizeof(sa
);
1355 sa
.lpSecurityDescriptor
= NULL
;
1356 sa
.bInheritHandle
= TRUE
;
1358 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1359 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1361 /* first, we need to be sure we're attached to a console */
1362 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1364 /* we're not attached to a console, let's do it */
1366 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1367 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1369 /* now verify everything's ok */
1370 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1371 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1372 startup
.hStdError
= startup
.hStdOutput
;
1374 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1375 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
) &&
1376 GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console modes\n");
1377 cpIn
= GetConsoleCP();
1378 cpOut
= GetConsoleOutputCP();
1380 get_file_name(resfile
);
1381 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" console", selfname
, resfile
);
1382 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1384 /* wait for child to terminate */
1385 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1386 /* child process has changed result file, so let profile functions know about it */
1387 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1389 /* now get the modification the child has made, and resets parents expected values */
1390 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1391 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
) &&
1392 GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console modes\n");
1394 SetConsoleMode(startup
.hStdInput
, modeIn
);
1395 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1397 cpInC
= GetConsoleCP();
1398 cpOutC
= GetConsoleOutputCP();
1400 /* Try to set invalid CP */
1401 SetLastError(0xdeadbeef);
1402 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1403 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1404 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1405 "GetLastError: expecting %u got %u\n",
1406 ERROR_INVALID_PARAMETER
, GetLastError());
1407 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1411 SetLastError(0xdeadbeef);
1412 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1413 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1414 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1415 "GetLastError: expecting %u got %u\n",
1416 ERROR_INVALID_PARAMETER
, GetLastError());
1419 SetConsoleOutputCP(cpOut
);
1421 GetStartupInfoA(&us
);
1423 okChildInt("StartupInfoA", "cb", startup
.cb
);
1424 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1425 result
= getChildString( "StartupInfoA", "lpTitle" );
1426 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1427 "expected '%s' or null, got '%s'\n", selfname
, result
);
1428 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1429 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1430 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1431 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1432 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1433 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1434 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1435 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1436 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1438 /* check child correctly inherited the console */
1439 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1440 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1441 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1442 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1443 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1444 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1445 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1446 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1447 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1448 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1449 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1450 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1451 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1452 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1453 okChildInt("Console", "InputCP", cpIn
);
1454 okChildInt("Console", "OutputCP", cpOut
);
1455 okChildInt("Console", "InputMode", modeIn
);
1456 okChildInt("Console", "OutputMode", modeOut
);
1460 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1461 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1464 win_skip("Setting the codepage is not implemented\n");
1466 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1467 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1468 trace("cursor position(X): %d/%d\n",sbi
.dwCursorPosition
.X
, sbiC
.dwCursorPosition
.X
);
1469 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1472 assert(DeleteFileA(resfile
) != 0);
1474 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1475 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1476 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1477 "Duplicating as inheritable child-output pipe\n");
1478 CloseHandle(hChildOut
);
1480 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1481 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1482 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1483 "Duplicating as inheritable child-input pipe\n");
1484 CloseHandle(hChildIn
);
1486 memset(&startup
, 0, sizeof(startup
));
1487 startup
.cb
= sizeof(startup
);
1488 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1489 startup
.wShowWindow
= SW_SHOWNORMAL
;
1490 startup
.hStdInput
= hChildInInh
;
1491 startup
.hStdOutput
= hChildOutInh
;
1492 startup
.hStdError
= hChildOutInh
;
1494 get_file_name(resfile
);
1495 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname
, resfile
);
1496 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1497 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1498 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1500 msg_len
= strlen(msg
) + 1;
1501 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1502 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1503 memset(buffer
, 0, sizeof(buffer
));
1504 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1505 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1507 /* wait for child to terminate */
1508 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1509 /* child process has changed result file, so let profile functions know about it */
1510 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1512 okChildString("StdHandle", "msg", msg
);
1515 assert(DeleteFileA(resfile
) != 0);
1518 static void test_ExitCode(void)
1520 char buffer
[MAX_PATH
];
1521 PROCESS_INFORMATION info
;
1522 STARTUPINFOA startup
;
1525 /* let's start simplistic */
1526 memset(&startup
, 0, sizeof(startup
));
1527 startup
.cb
= sizeof(startup
);
1528 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1529 startup
.wShowWindow
= SW_SHOWNORMAL
;
1531 get_file_name(resfile
);
1532 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname
, resfile
);
1533 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1535 /* wait for child to terminate */
1536 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1537 /* child process has changed result file, so let profile functions know about it */
1538 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1540 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1541 okChildInt("ExitCode", "value", code
);
1544 assert(DeleteFileA(resfile
) != 0);
1547 static void test_OpenProcess(void)
1551 MEMORY_BASIC_INFORMATION info
;
1552 SIZE_T dummy
, read_bytes
;
1555 /* not exported in all windows versions */
1556 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1557 win_skip("VirtualAllocEx not found\n");
1561 /* without PROCESS_VM_OPERATION */
1562 hproc
= OpenProcess(PROCESS_ALL_ACCESS_NT4
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1563 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1565 SetLastError(0xdeadbeef);
1566 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1567 ok(!addr1
, "VirtualAllocEx should fail\n");
1568 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1571 win_skip("VirtualAllocEx not implemented\n");
1574 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1576 read_bytes
= 0xdeadbeef;
1577 SetLastError(0xdeadbeef);
1578 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1579 ok(ret
, "ReadProcessMemory error %d\n", GetLastError());
1580 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1584 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1585 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1587 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1588 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1590 /* without PROCESS_QUERY_INFORMATION */
1591 SetLastError(0xdeadbeef);
1592 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1593 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1594 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1596 /* without PROCESS_VM_READ */
1597 read_bytes
= 0xdeadbeef;
1598 SetLastError(0xdeadbeef);
1599 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1600 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1601 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1602 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1606 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1608 memset(&info
, 0xcc, sizeof(info
));
1609 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1610 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1612 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1613 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1614 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1615 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1616 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1617 /* NT reports Protect == 0 for a not committed memory block */
1618 ok(info
.Protect
== 0 /* NT */ ||
1619 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1620 "%x != PAGE_NOACCESS\n", info
.Protect
);
1621 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1623 SetLastError(0xdeadbeef);
1624 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1625 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1626 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1630 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
1633 SetLastError(0xdeadbeef);
1634 memset(&info
, 0xcc, sizeof(info
));
1635 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1636 if (read_bytes
) /* win8 */
1638 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1639 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1640 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1641 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1642 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1643 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1644 ok(info
.Protect
== 0, "%x != PAGE_NOACCESS\n", info
.Protect
);
1645 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1647 else /* before win8 */
1648 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1650 SetLastError(0xdeadbeef);
1651 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1652 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1653 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1658 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1661 static void test_GetProcessVersion(void)
1663 static char cmdline
[] = "winver.exe";
1664 PROCESS_INFORMATION pi
;
1668 SetLastError(0xdeadbeef);
1669 ret
= GetProcessVersion(0);
1670 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1672 SetLastError(0xdeadbeef);
1673 ret
= GetProcessVersion(GetCurrentProcessId());
1674 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1676 memset(&si
, 0, sizeof(si
));
1678 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1679 si
.wShowWindow
= SW_HIDE
;
1680 SetLastError(0xdeadbeef);
1681 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1682 ok(ret
, "CreateProcess error %u\n", GetLastError());
1684 SetLastError(0xdeadbeef);
1685 ret
= GetProcessVersion(pi
.dwProcessId
);
1686 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1688 SetLastError(0xdeadbeef);
1689 ret
= TerminateProcess(pi
.hProcess
, 0);
1690 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1692 CloseHandle(pi
.hProcess
);
1693 CloseHandle(pi
.hThread
);
1696 static void test_GetProcessImageFileNameA(void)
1699 CHAR process
[MAX_PATH
];
1700 static const char harddisk
[] = "\\Device\\HarddiskVolume";
1702 if (!pK32GetProcessImageFileNameA
)
1704 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1708 /* callers must guess the buffer size */
1709 SetLastError(0xdeadbeef);
1710 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL
, 0);
1711 ok(!rc
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
1712 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc
, GetLastError());
1715 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), process
, sizeof(process
));
1716 expect_eq_d(rc
, lstrlenA(process
));
1717 if (strncmp(process
, harddisk
, lstrlenA(harddisk
)))
1719 todo_wine
win_skip("%s is probably on a network share, skipping tests\n", process
);
1723 if (!pQueryFullProcessImageNameA
)
1724 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1727 CHAR image
[MAX_PATH
];
1730 length
= sizeof(image
);
1731 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE
, image
, &length
));
1732 expect_eq_d(length
, lstrlenA(image
));
1733 ok(lstrcmpiA(process
, image
) == 0, "expected '%s' to be equal to '%s'\n", process
, image
);
1737 static void test_QueryFullProcessImageNameA(void)
1739 #define INIT_STR "Just some words"
1741 CHAR buf
[MAX_PATH
], module
[MAX_PATH
];
1743 if (!pQueryFullProcessImageNameA
)
1745 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1750 SetLastError(0); /* old Windows don't reset it on success */
1751 size
= GetModuleFileNameA(NULL
, module
, sizeof(module
));
1752 ok(size
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
, "GetModuleFileName failed: %u le=%u\n", size
, GetLastError());
1754 /* get the buffer length without \0 terminator */
1755 length
= sizeof(buf
);
1756 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1757 expect_eq_d(length
, lstrlenA(buf
));
1758 ok((buf
[0] == '\\' && buf
[1] == '\\') ||
1759 lstrcmpiA(buf
, module
) == 0, "expected %s to match %s\n", buf
, module
);
1761 /* when the buffer is too small
1762 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1763 * - the size variable is not modified
1764 * tested with the biggest too small size
1767 sprintf(buf
,INIT_STR
);
1768 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1769 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1770 expect_eq_d(length
, size
);
1771 expect_eq_s(INIT_STR
, buf
);
1773 /* retest with smaller buffer size
1776 sprintf(buf
,INIT_STR
);
1777 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1778 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1779 expect_eq_d(4, size
);
1780 expect_eq_s(INIT_STR
, buf
);
1782 /* this is a difference between the ascii and the unicode version
1783 * the unicode version crashes when the size is big enough to hold
1784 * the result while the ascii version throws an error
1787 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1788 expect_eq_d(1024, size
);
1789 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1792 static void test_QueryFullProcessImageNameW(void)
1795 WCHAR module_name
[1024], device
[1024];
1796 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
1800 if (!pQueryFullProcessImageNameW
)
1802 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1806 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1808 /* GetCurrentProcess pseudo-handle */
1809 size
= sizeof(buf
) / sizeof(buf
[0]);
1810 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
1811 expect_eq_d(lstrlenW(buf
), size
);
1812 expect_eq_ws_i(buf
, module_name
);
1814 hSelf
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1816 size
= sizeof(buf
) / sizeof(buf
[0]);
1817 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1818 expect_eq_d(lstrlenW(buf
), size
);
1819 expect_eq_ws_i(buf
, module_name
);
1821 /* Buffer too small */
1822 size
= lstrlenW(module_name
)/2;
1823 lstrcpyW(buf
, deviceW
);
1824 SetLastError(0xdeadbeef);
1825 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1826 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1827 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1828 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
1830 /* Too small - not space for NUL terminator */
1831 size
= lstrlenW(module_name
);
1832 SetLastError(0xdeadbeef);
1833 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1834 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
1835 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1839 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
1840 expect_eq_d(0, size
);
1841 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1843 /* Buffer too small */
1844 size
= lstrlenW(module_name
)/2;
1845 SetLastError(0xdeadbeef);
1846 lstrcpyW(buf
, module_name
);
1847 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1848 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1849 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1850 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
1854 size
= sizeof(buf
) / sizeof(buf
[0]);
1855 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
1856 expect_eq_d(lstrlenW(buf
), size
);
1857 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
1858 ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
1860 module_name
[2] = '\0';
1862 size
= QueryDosDeviceW(module_name
, device
, sizeof(device
)/sizeof(device
[0]));
1863 ok(size
, "QueryDosDeviceW failed: le=%u\n", GetLastError());
1864 len
= lstrlenW(device
);
1865 ok(size
>= len
+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size
, len
, wine_dbgstr_w(device
));
1867 if (size
>= lstrlenW(buf
))
1869 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
1873 ok(buf
[len
] == '\\', "expected '%c' to be a '\\' in %s\n", buf
[len
], wine_dbgstr_w(module_name
));
1875 ok(lstrcmpiW(device
, buf
) == 0, "expected %s to match %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
1876 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));
1882 static void test_Handles(void)
1884 HANDLE handle
= GetCurrentProcess();
1889 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
1890 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
1891 "invalid current process handle %p\n", handle
);
1892 ret
= GetExitCodeProcess( handle
, &code
);
1893 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1895 /* truncated handle */
1896 SetLastError( 0xdeadbeef );
1897 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
1898 ret
= GetExitCodeProcess( handle
, &code
);
1899 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1900 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1901 /* sign-extended handle */
1902 SetLastError( 0xdeadbeef );
1903 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
1904 ret
= GetExitCodeProcess( handle
, &code
);
1905 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1906 /* invalid high-word */
1907 SetLastError( 0xdeadbeef );
1908 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
1909 ret
= GetExitCodeProcess( handle
, &code
);
1910 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1911 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1914 handle
= GetStdHandle( STD_ERROR_HANDLE
);
1915 ok( handle
!= 0, "handle %p\n", handle
);
1916 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
1917 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1918 SetStdHandle( STD_ERROR_HANDLE
, h3
);
1919 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
1920 h2
= GetStdHandle( STD_ERROR_HANDLE
);
1922 broken( h2
== h3
) || /* nt4, w2k */
1923 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
1924 "wrong handle %p/%p\n", h2
, h3
);
1925 SetStdHandle( STD_ERROR_HANDLE
, handle
);
1928 static void test_IsWow64Process(void)
1930 PROCESS_INFORMATION pi
;
1934 static char cmdline
[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
1935 static char cmdline_wow64
[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
1937 if (!pIsWow64Process
)
1939 skip("IsWow64Process is not available\n");
1943 memset(&si
, 0, sizeof(si
));
1945 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1946 si
.wShowWindow
= SW_HIDE
;
1947 ret
= CreateProcessA(NULL
, cmdline_wow64
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1950 trace("Created process %s\n", cmdline_wow64
);
1952 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
1953 ok(ret
, "IsWow64Process failed.\n");
1954 ok(is_wow64
, "is_wow64 returned FALSE.\n");
1956 ret
= TerminateProcess(pi
.hProcess
, 0);
1957 ok(ret
, "TerminateProcess error\n");
1959 CloseHandle(pi
.hProcess
);
1960 CloseHandle(pi
.hThread
);
1963 memset(&si
, 0, sizeof(si
));
1965 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1966 si
.wShowWindow
= SW_HIDE
;
1967 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1970 trace("Created process %s\n", cmdline
);
1972 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
1973 ok(ret
, "IsWow64Process failed.\n");
1974 ok(!is_wow64
, "is_wow64 returned TRUE.\n");
1976 ret
= TerminateProcess(pi
.hProcess
, 0);
1977 ok(ret
, "TerminateProcess error\n");
1979 CloseHandle(pi
.hProcess
);
1980 CloseHandle(pi
.hThread
);
1984 static void test_SystemInfo(void)
1986 SYSTEM_INFO si
, nsi
;
1989 if (!pGetNativeSystemInfo
)
1991 win_skip("GetNativeSystemInfo is not available\n");
1995 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
1998 pGetNativeSystemInfo(&nsi
);
2001 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
2003 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
2004 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
2005 S(U(nsi
)).wProcessorArchitecture
);
2006 ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
,
2007 "Expected PROCESSOR_AMD_X8664, got %d\n",
2008 nsi
.dwProcessorType
);
2013 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
2014 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
2015 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
2016 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
2017 "Expected no difference for dwProcessorType, got %d and %d\n",
2018 si
.dwProcessorType
, nsi
.dwProcessorType
);
2022 static void test_RegistryQuota(void)
2025 DWORD max_quota
, used_quota
;
2027 if (!pGetSystemRegistryQuota
)
2029 win_skip("GetSystemRegistryQuota is not available\n");
2033 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
2035 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2037 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
2039 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2041 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
2043 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2045 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
2047 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2050 static void test_TerminateProcess(void)
2052 static char cmdline
[] = "winver.exe";
2053 PROCESS_INFORMATION pi
;
2056 HANDLE dummy
, thread
;
2058 memset(&si
, 0, sizeof(si
));
2060 SetLastError(0xdeadbeef);
2061 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2062 ok(ret
, "CreateProcess error %u\n", GetLastError());
2064 SetLastError(0xdeadbeef);
2065 thread
= CreateRemoteThread(pi
.hProcess
, NULL
, 0, (void *)0xdeadbeef, NULL
, CREATE_SUSPENDED
, &ret
);
2066 ok(thread
!= 0, "CreateRemoteThread error %d\n", GetLastError());
2068 /* create a not closed thread handle duplicate in the target process */
2069 SetLastError(0xdeadbeef);
2070 ret
= DuplicateHandle(GetCurrentProcess(), thread
, pi
.hProcess
, &dummy
,
2071 0, FALSE
, DUPLICATE_SAME_ACCESS
);
2072 ok(ret
, "DuplicateHandle error %u\n", GetLastError());
2074 SetLastError(0xdeadbeef);
2075 ret
= TerminateThread(thread
, 0);
2076 ok(ret
, "TerminateThread error %u\n", GetLastError());
2077 CloseHandle(thread
);
2079 SetLastError(0xdeadbeef);
2080 ret
= TerminateProcess(pi
.hProcess
, 0);
2081 ok(ret
, "TerminateProcess error %u\n", GetLastError());
2083 CloseHandle(pi
.hProcess
);
2084 CloseHandle(pi
.hThread
);
2087 static void test_DuplicateHandle(void)
2089 char path
[MAX_PATH
], file_name
[MAX_PATH
];
2090 HANDLE f
, fmin
, out
;
2094 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2095 GetCurrentProcess(), &out
, 0, FALSE
,
2096 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2097 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2098 r
= GetHandleInformation(out
, &info
);
2099 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2100 ok(info
== 0, "info = %x\n", info
);
2101 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2104 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2105 GetCurrentProcess(), &out
, 0, TRUE
,
2106 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2107 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2108 r
= GetHandleInformation(out
, &info
);
2109 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2110 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2111 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2114 GetTempPathA(MAX_PATH
, path
);
2115 GetTempFileNameA(path
, "wt", 0, file_name
);
2116 f
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
2117 if (f
== INVALID_HANDLE_VALUE
)
2119 ok(0, "could not create %s\n", file_name
);
2123 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2124 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2125 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2126 ok(f
== out
, "f != out\n");
2127 r
= GetHandleInformation(out
, &info
);
2128 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2129 ok(info
== 0, "info = %x\n", info
);
2131 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2132 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2133 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2134 ok(f
== out
, "f != out\n");
2135 r
= GetHandleInformation(out
, &info
);
2136 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2137 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2139 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, HANDLE_FLAG_PROTECT_FROM_CLOSE
);
2140 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2141 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2142 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2143 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2144 ok(f
!= out
, "f == out\n");
2145 r
= GetHandleInformation(out
, &info
);
2146 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2147 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2148 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, 0);
2149 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2151 /* Test if DuplicateHandle allocates first free handle */
2162 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2163 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2164 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2165 ok(f
== out
, "f != out\n");
2167 DeleteFileA(file_name
);
2169 f
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2172 skip("DuplicateHandle on console handle\n");
2177 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2178 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2179 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2180 todo_wine
ok(f
!= out
, "f == out\n");
2184 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2185 static void _test_completion(int line
, HANDLE port
, DWORD ekey
, ULONG_PTR evalue
, ULONG_PTR eoverlapped
, DWORD wait
)
2187 LPOVERLAPPED overlapped
;
2192 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, wait
);
2194 ok_(__FILE__
, line
)(ret
, "GetQueuedCompletionStatus: %x\n", GetLastError());
2197 ok_(__FILE__
, line
)(key
== ekey
, "unexpected key %x\n", key
);
2198 ok_(__FILE__
, line
)(value
== evalue
, "unexpected value %p\n", (void *)value
);
2199 ok_(__FILE__
, line
)(overlapped
== (LPOVERLAPPED
)eoverlapped
, "unexpected overlapped %p\n", overlapped
);
2203 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2204 static void _create_process(int line
, const char *command
, LPPROCESS_INFORMATION pi
)
2207 char buffer
[MAX_PATH
];
2208 STARTUPINFOA si
= {0};
2210 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, command
);
2212 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, pi
);
2213 ok_(__FILE__
, line
)(ret
, "CreateProcess error %u\n", GetLastError());
2217 static void test_IsProcessInJob(void)
2220 PROCESS_INFORMATION pi
;
2224 if (!pIsProcessInJob
)
2226 win_skip("IsProcessInJob not available.\n");
2230 job
= pCreateJobObjectW(NULL
, NULL
);
2231 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2233 job2
= pCreateJobObjectW(NULL
, NULL
);
2234 ok(job2
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2236 create_process("wait", &pi
);
2239 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2240 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2241 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2244 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2245 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2246 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2249 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2250 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2251 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2253 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2254 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2257 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2258 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2259 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2262 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2263 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2264 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2267 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2268 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2269 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2271 TerminateProcess(pi
.hProcess
, 0);
2273 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2274 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2277 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2278 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2279 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2281 CloseHandle(pi
.hProcess
);
2282 CloseHandle(pi
.hThread
);
2287 static void test_TerminateJobObject(void)
2290 PROCESS_INFORMATION pi
;
2294 job
= pCreateJobObjectW(NULL
, NULL
);
2295 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2297 create_process("wait", &pi
);
2299 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2300 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2302 ret
= pTerminateJobObject(job
, 123);
2303 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2305 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2306 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2307 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2309 ret
= GetExitCodeProcess(pi
.hProcess
, &dwret
);
2310 ok(ret
, "GetExitCodeProcess error %u\n", GetLastError());
2311 ok(dwret
== 123 || broken(dwret
== 0) /* randomly fails on Win 2000 / XP */,
2312 "wrong exitcode %u\n", dwret
);
2314 CloseHandle(pi
.hProcess
);
2315 CloseHandle(pi
.hThread
);
2317 /* Test adding an already terminated process to a job object */
2318 create_process("exit", &pi
);
2320 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2321 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2323 SetLastError(0xdeadbeef);
2324 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2325 ok(!ret
, "AssignProcessToJobObject unexpectedly succeeded\n");
2326 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2328 CloseHandle(pi
.hProcess
);
2329 CloseHandle(pi
.hThread
);
2334 static void test_QueryInformationJobObject(void)
2336 char buf
[sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST
) + sizeof(ULONG_PTR
) * 4];
2337 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2338 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ext_limit_info
;
2339 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit_info
= &ext_limit_info
.BasicLimitInformation
;
2340 DWORD dwret
, ret_len
;
2341 PROCESS_INFORMATION pi
[2];
2345 job
= pCreateJobObjectW(NULL
, NULL
);
2346 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2348 /* Only active processes are returned */
2349 create_process("exit", &pi
[0]);
2350 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2351 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2352 dwret
= WaitForSingleObject(pi
[0].hProcess
, 1000);
2353 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2355 CloseHandle(pi
[0].hProcess
);
2356 CloseHandle(pi
[0].hThread
);
2358 create_process("wait", &pi
[0]);
2359 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2360 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2362 create_process("wait", &pi
[1]);
2363 ret
= pAssignProcessToJobObject(job
, pi
[1].hProcess
);
2364 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2366 SetLastError(0xdeadbeef);
2367 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2368 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
), &ret_len
);
2369 ok(!ret
, "QueryInformationJobObject expected failure\n");
2371 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2373 SetLastError(0xdeadbeef);
2374 memset(buf
, 0, sizeof(buf
));
2375 pid_list
->NumberOfAssignedProcesses
= 42;
2376 pid_list
->NumberOfProcessIdsInList
= 42;
2377 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2378 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[1]), &ret_len
);
2379 ok(!ret
, "QueryInformationJobObject expected failure\n");
2381 expect_eq_d(ERROR_MORE_DATA
, GetLastError());
2384 expect_eq_d(42, pid_list
->NumberOfAssignedProcesses
);
2385 expect_eq_d(42, pid_list
->NumberOfProcessIdsInList
);
2388 memset(buf
, 0, sizeof(buf
));
2389 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2391 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2394 if (pid_list
->NumberOfAssignedProcesses
== 3) /* Win 8 */
2395 win_skip("Number of assigned processes broken on Win 8\n");
2398 ULONG_PTR
*list
= pid_list
->ProcessIdList
;
2400 ok(ret_len
== FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[2]),
2401 "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2403 expect_eq_d(2, pid_list
->NumberOfAssignedProcesses
);
2404 expect_eq_d(2, pid_list
->NumberOfProcessIdsInList
);
2405 expect_eq_d(pi
[0].dwProcessId
, list
[0]);
2406 expect_eq_d(pi
[1].dwProcessId
, list
[1]);
2410 /* test JobObjectBasicLimitInformation */
2411 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2412 sizeof(*basic_limit_info
) - 1, &ret_len
);
2413 ok(!ret
, "QueryInformationJobObject expected failure\n");
2414 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2416 ret_len
= 0xdeadbeef;
2417 memset(basic_limit_info
, 0x11, sizeof(*basic_limit_info
));
2418 ret
= pQueryInformationJobObject(job
, JobObjectBasicLimitInformation
, basic_limit_info
,
2419 sizeof(*basic_limit_info
), &ret_len
);
2420 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2421 ok(ret_len
== sizeof(*basic_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2422 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2424 /* test JobObjectExtendedLimitInformation */
2425 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2426 sizeof(ext_limit_info
) - 1, &ret_len
);
2427 ok(!ret
, "QueryInformationJobObject expected failure\n");
2428 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2430 ret_len
= 0xdeadbeef;
2431 memset(&ext_limit_info
, 0x11, sizeof(ext_limit_info
));
2432 ret
= pQueryInformationJobObject(job
, JobObjectExtendedLimitInformation
, &ext_limit_info
,
2433 sizeof(ext_limit_info
), &ret_len
);
2434 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2435 ok(ret_len
== sizeof(ext_limit_info
), "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2436 expect_eq_d(0, basic_limit_info
->LimitFlags
);
2438 TerminateProcess(pi
[0].hProcess
, 0);
2439 CloseHandle(pi
[0].hProcess
);
2440 CloseHandle(pi
[0].hThread
);
2442 TerminateProcess(pi
[1].hProcess
, 0);
2443 CloseHandle(pi
[1].hProcess
);
2444 CloseHandle(pi
[1].hThread
);
2449 static void test_CompletionPort(void)
2451 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
2452 PROCESS_INFORMATION pi
;
2457 job
= pCreateJobObjectW(NULL
, NULL
);
2458 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2460 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
2461 ok(port
!= NULL
, "CreateIoCompletionPort error %u\n", GetLastError());
2463 port_info
.CompletionKey
= job
;
2464 port_info
.CompletionPort
= port
;
2465 ret
= pSetInformationJobObject(job
, JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
2466 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2468 create_process("wait", &pi
);
2470 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2471 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2473 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2475 TerminateProcess(pi
.hProcess
, 0);
2476 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2477 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2479 test_completion(port
, JOB_OBJECT_MSG_EXIT_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2480 test_completion(port
, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
, (DWORD_PTR
)job
, 0, 100);
2482 CloseHandle(pi
.hProcess
);
2483 CloseHandle(pi
.hThread
);
2488 static void test_KillOnJobClose(void)
2490 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2491 PROCESS_INFORMATION pi
;
2496 job
= pCreateJobObjectW(NULL
, NULL
);
2497 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2499 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
;
2500 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2501 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
2503 win_skip("Kill on job close limit not available\n");
2506 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2508 create_process("wait", &pi
);
2510 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2511 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2515 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2516 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2517 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2519 CloseHandle(pi
.hProcess
);
2520 CloseHandle(pi
.hThread
);
2523 static void test_WaitForJobObject(void)
2526 PROCESS_INFORMATION pi
;
2530 /* test waiting for a job object when the process is killed */
2531 job
= pCreateJobObjectW(NULL
, NULL
);
2532 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2534 dwret
= WaitForSingleObject(job
, 100);
2535 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2537 create_process("wait", &pi
);
2539 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2540 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2542 dwret
= WaitForSingleObject(job
, 100);
2543 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2545 ret
= pTerminateJobObject(job
, 123);
2546 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2548 dwret
= WaitForSingleObject(job
, 500);
2549 ok(dwret
== WAIT_OBJECT_0
|| broken(dwret
== WAIT_TIMEOUT
),
2550 "WaitForSingleObject returned %u\n", dwret
);
2552 if (dwret
== WAIT_TIMEOUT
) /* Win 2000/XP */
2554 CloseHandle(pi
.hProcess
);
2555 CloseHandle(pi
.hThread
);
2557 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2561 /* the object is not reset immediately */
2562 dwret
= WaitForSingleObject(job
, 100);
2563 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2565 CloseHandle(pi
.hProcess
);
2566 CloseHandle(pi
.hThread
);
2568 /* creating a new process doesn't reset the signalled state */
2569 create_process("wait", &pi
);
2571 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2572 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2574 dwret
= WaitForSingleObject(job
, 100);
2575 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2577 ret
= pTerminateJobObject(job
, 123);
2578 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2580 CloseHandle(pi
.hProcess
);
2581 CloseHandle(pi
.hThread
);
2585 /* repeat the test, but this time the process terminates properly */
2586 job
= pCreateJobObjectW(NULL
, NULL
);
2587 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2589 dwret
= WaitForSingleObject(job
, 100);
2590 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2592 create_process("exit", &pi
);
2594 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2595 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2597 dwret
= WaitForSingleObject(job
, 100);
2598 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2600 CloseHandle(pi
.hProcess
);
2601 CloseHandle(pi
.hThread
);
2605 static HANDLE
test_AddSelfToJob(void)
2610 job
= pCreateJobObjectW(NULL
, NULL
);
2611 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2613 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
2614 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2619 static void test_jobInheritance(HANDLE job
)
2621 char buffer
[MAX_PATH
];
2622 PROCESS_INFORMATION pi
;
2623 STARTUPINFOA si
= {0};
2627 if (!pIsProcessInJob
)
2629 win_skip("IsProcessInJob not available.\n");
2633 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2635 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2636 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2639 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2640 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2641 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2643 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2644 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2646 CloseHandle(pi
.hProcess
);
2647 CloseHandle(pi
.hThread
);
2650 static void test_BreakawayOk(HANDLE job
)
2652 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2653 PROCESS_INFORMATION pi
;
2654 STARTUPINFOA si
= {0};
2655 char buffer
[MAX_PATH
];
2659 if (!pIsProcessInJob
)
2661 win_skip("IsProcessInJob not available.\n");
2665 sprintf(buffer
, "\"%s\" tests/process.c %s", selfname
, "exit");
2667 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2668 ok(!ret
, "CreateProcessA expected failure\n");
2669 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2673 TerminateProcess(pi
.hProcess
, 0);
2675 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2676 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2678 CloseHandle(pi
.hProcess
);
2679 CloseHandle(pi
.hThread
);
2682 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
2683 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2684 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2686 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2687 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2689 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2690 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2691 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2693 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2694 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2696 CloseHandle(pi
.hProcess
);
2697 CloseHandle(pi
.hThread
);
2699 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
2700 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2701 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2703 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2704 ok(ret
, "CreateProcess error %u\n", GetLastError());
2706 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2707 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2708 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2710 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2711 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2713 CloseHandle(pi
.hProcess
);
2714 CloseHandle(pi
.hThread
);
2716 /* unset breakaway ok */
2717 limit_info
.BasicLimitInformation
.LimitFlags
= 0;
2718 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2719 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2722 static void test_StartupNoConsole(void)
2725 char buffer
[MAX_PATH
];
2726 STARTUPINFOA startup
;
2727 PROCESS_INFORMATION info
;
2732 win_skip( "NtCurrentTeb not supported\n" );
2736 memset(&startup
, 0, sizeof(startup
));
2737 startup
.cb
= sizeof(startup
);
2738 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
2739 startup
.wShowWindow
= SW_SHOWNORMAL
;
2740 get_file_name(resfile
);
2741 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
2742 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
2743 &info
), "CreateProcess\n");
2744 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
2745 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
2746 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
2747 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
2748 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
2749 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
2750 okChildInt("TEB", "hStdInput", 0);
2751 okChildInt("TEB", "hStdOutput", 0);
2752 okChildInt("TEB", "hStdError", 0);
2754 DeleteFileA(resfile
);
2758 static void test_GetNumaProcessorNode(void)
2765 if (!pGetNumaProcessorNode
)
2767 win_skip("GetNumaProcessorNode is missing\n");
2772 for (i
= 0; i
< 256; i
++)
2774 SetLastError(0xdeadbeef);
2775 node
= (i
< si
.dwNumberOfProcessors
) ? 0xFF : 0xAA;
2776 ret
= pGetNumaProcessorNode(i
, &node
);
2777 if (i
< si
.dwNumberOfProcessors
)
2779 ok(ret
, "GetNumaProcessorNode returned FALSE for processor %d\n", i
);
2780 ok(node
!= 0xFF, "expected node != 0xFF, but got 0xFF\n");
2784 ok(!ret
, "GetNumaProcessorNode returned TRUE for processor %d\n", i
);
2785 ok(node
== 0xFF || broken(node
== 0xAA) /* WinXP */, "expected node 0xFF, got %x\n", node
);
2786 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2791 static void test_process_info(void)
2794 static const ULONG info_size
[] =
2796 sizeof(PROCESS_BASIC_INFORMATION
) /* ProcessBasicInformation */,
2797 sizeof(QUOTA_LIMITS
) /* ProcessQuotaLimits */,
2798 sizeof(IO_COUNTERS
) /* ProcessIoCounters */,
2799 sizeof(VM_COUNTERS
) /* ProcessVmCounters */,
2800 sizeof(KERNEL_USER_TIMES
) /* ProcessTimes */,
2801 sizeof(ULONG
) /* ProcessBasePriority */,
2802 sizeof(ULONG
) /* ProcessRaisePriority */,
2803 sizeof(HANDLE
) /* ProcessDebugPort */,
2804 sizeof(HANDLE
) /* ProcessExceptionPort */,
2805 0 /* FIXME: sizeof(PROCESS_ACCESS_TOKEN) ProcessAccessToken */,
2806 0 /* FIXME: sizeof(PROCESS_LDT_INFORMATION) ProcessLdtInformation */,
2807 0 /* FIXME: sizeof(PROCESS_LDT_SIZE) ProcessLdtSize */,
2808 sizeof(ULONG
) /* ProcessDefaultHardErrorMode */,
2809 0 /* ProcessIoPortHandlers: kernel-mode only */,
2810 0 /* FIXME: sizeof(POOLED_USAGE_AND_LIMITS) ProcessPooledUsageAndLimits */,
2811 0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION) ProcessWorkingSetWatch */,
2812 sizeof(ULONG
) /* ProcessUserModeIOPL */,
2813 sizeof(BOOLEAN
) /* ProcessEnableAlignmentFaultFixup */,
2814 sizeof(PROCESS_PRIORITY_CLASS
) /* ProcessPriorityClass */,
2815 sizeof(ULONG
) /* ProcessWx86Information */,
2816 sizeof(ULONG
) /* ProcessHandleCount */,
2817 sizeof(ULONG_PTR
) /* ProcessAffinityMask */,
2818 sizeof(ULONG
) /* ProcessPriorityBoost */,
2819 0 /* sizeof(PROCESS_DEVICEMAP_INFORMATION) ProcessDeviceMap */,
2820 0 /* sizeof(PROCESS_SESSION_INFORMATION) ProcessSessionInformation */,
2821 0 /* sizeof(PROCESS_FOREGROUND_BACKGROUND) ProcessForegroundInformation */,
2822 sizeof(ULONG_PTR
) /* ProcessWow64Information */,
2823 sizeof(buf
) /* ProcessImageFileName */,
2824 sizeof(ULONG
) /* ProcessLUIDDeviceMapsEnabled */,
2825 sizeof(ULONG
) /* ProcessBreakOnTermination */,
2826 sizeof(HANDLE
) /* ProcessDebugObjectHandle */,
2827 sizeof(ULONG
) /* ProcessDebugFlags */,
2828 sizeof(buf
) /* ProcessHandleTracing */,
2829 sizeof(ULONG
) /* ProcessIoPriority */,
2830 sizeof(ULONG
) /* ProcessExecuteFlags */,
2831 #if 0 /* FIXME: Add remaning classes */
2832 ProcessResourceManagement
,
2833 sizeof(ULONG
) /* ProcessCookie */,
2834 sizeof(SECTION_IMAGE_INFORMATION
) /* ProcessImageInformation */,
2835 sizeof(PROCESS_CYCLE_TIME_INFORMATION
) /* ProcessCycleTime */,
2836 sizeof(ULONG
) /* ProcessPagePriority */,
2837 40 /* ProcessInstrumentationCallback */,
2838 sizeof(PROCESS_STACK_ALLOCATION_INFORMATION
) /* ProcessThreadStackAllocation */,
2839 sizeof(PROCESS_WS_WATCH_INFORMATION_EX
[]) /* ProcessWorkingSetWatchEx */,
2840 sizeof(buf
) /* ProcessImageFileNameWin32 */,
2841 sizeof(HANDLE
) /* ProcessImageFileMapping */,
2842 sizeof(PROCESS_AFFINITY_UPDATE_MODE
) /* ProcessAffinityUpdateMode */,
2843 sizeof(PROCESS_MEMORY_ALLOCATION_MODE
) /* ProcessMemoryAllocationMode */,
2844 sizeof(USHORT
[]) /* ProcessGroupInformation */,
2845 sizeof(ULONG
) /* ProcessTokenVirtualizationEnabled */,
2846 sizeof(ULONG_PTR
) /* ProcessConsoleHostProcess */,
2847 sizeof(PROCESS_WINDOW_INFORMATION
) /* ProcessWindowInformation */,
2848 sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION
) /* ProcessHandleInformation */,
2849 sizeof(PROCESS_MITIGATION_POLICY_INFORMATION
) /* ProcessMitigationPolicy */,
2850 sizeof(ProcessDynamicFunctionTableInformation
) /* ProcessDynamicFunctionTableInformation */,
2851 sizeof(?) /* ProcessHandleCheckingMode */,
2852 sizeof(PROCESS_KEEPALIVE_COUNT_INFORMATION
) /* ProcessKeepAliveCount */,
2853 sizeof(PROCESS_REVOKE_FILE_HANDLES_INFORMATION
) /* ProcessRevokeFileHandles */,
2854 sizeof(PROCESS_WORKING_SET_CONTROL
) /* ProcessWorkingSetControl */,
2855 sizeof(?) /* ProcessHandleTable */,
2856 sizeof(?) /* ProcessCheckStackExtentsMode */,
2857 sizeof(buf
) /* ProcessCommandLineInformation */,
2858 sizeof(PS_PROTECTION
) /* ProcessProtectionInformation */,
2859 sizeof(PROCESS_MEMORY_EXHAUSTION_INFO
) /* ProcessMemoryExhaustion */,
2860 sizeof(PROCESS_FAULT_INFORMATION
) /* ProcessFaultInformation */,
2861 sizeof(PROCESS_TELEMETRY_ID_INFORMATION
) /* ProcessTelemetryIdInformation */,
2862 sizeof(PROCESS_COMMIT_RELEASE_INFORMATION
) /* ProcessCommitReleaseInformation */,
2863 sizeof(?) /* ProcessDefaultCpuSetsInformation */,
2864 sizeof(?) /* ProcessAllowedCpuSetsInformation */,
2865 0 /* ProcessReserved1Information */,
2866 0 /* ProcessReserved2Information */,
2867 sizeof(?) /* ProcessSubsystemProcess */,
2868 sizeof(PROCESS_JOB_MEMORY_INFO
) /* ProcessJobMemoryInformation */,
2872 ULONG i
, status
, ret_len
, size
;
2874 if (!pNtQueryInformationProcess
)
2876 win_skip("NtQueryInformationProcess is not available on this platform\n");
2880 hproc
= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
, FALSE
, GetCurrentProcessId());
2883 win_skip("PROCESS_QUERY_LIMITED_INFORMATION is not supported on this platform\n");
2887 for (i
= 0; i
< MaxProcessInfoClass
; i
++)
2889 size
= info_size
[i
];
2890 if (!size
) size
= sizeof(buf
);
2892 status
= pNtQueryInformationProcess(hproc
, i
, buf
, info_size
[i
], &ret_len
);
2893 if (status
== STATUS_NOT_IMPLEMENTED
) continue;
2894 if (status
== STATUS_INVALID_INFO_CLASS
) continue;
2895 if (status
== STATUS_INFO_LENGTH_MISMATCH
) continue;
2899 case ProcessBasicInformation
:
2900 case ProcessQuotaLimits
:
2902 case ProcessPriorityClass
:
2903 case ProcessPriorityBoost
:
2904 case ProcessLUIDDeviceMapsEnabled
:
2905 case 33 /* ProcessIoPriority */:
2906 case ProcessIoCounters
:
2907 case ProcessVmCounters
:
2908 case ProcessWow64Information
:
2909 case ProcessDefaultHardErrorMode
:
2910 case ProcessHandleCount
:
2911 ok(status
== STATUS_SUCCESS
, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2914 case ProcessImageFileName
:
2916 ok(status
== STATUS_SUCCESS
, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2919 case ProcessAffinityMask
:
2920 case ProcessBreakOnTermination
:
2921 ok(status
== STATUS_ACCESS_DENIED
/* before win8 */ || status
== STATUS_SUCCESS
/* win8 is less strict */,
2922 "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2925 case ProcessDebugObjectHandle
:
2926 ok(status
== STATUS_ACCESS_DENIED
|| status
== STATUS_PORT_NOT_SET
,
2927 "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2930 case ProcessExecuteFlags
:
2931 case ProcessDebugPort
:
2932 case ProcessDebugFlags
:
2934 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2938 ok(status
== STATUS_ACCESS_DENIED
, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i
, status
, ret_len
);
2950 ok(b
, "Basic init of CreateProcess test\n");
2955 if (!strcmp(myARGV
[2], "dump") && myARGC
>= 4)
2957 doChild(myARGV
[3], (myARGC
>= 5) ? myARGV
[4] : NULL
);
2960 else if (!strcmp(myARGV
[2], "wait"))
2963 ok(0, "Child process not killed\n");
2966 else if (!strcmp(myARGV
[2], "exit"))
2972 ok(0, "Unexpected command %s\n", myARGV
[2]);
2975 test_process_info();
2976 test_TerminateProcess();
2982 test_DebuggingFlag();
2986 test_GetProcessVersion();
2987 test_GetProcessImageFileNameA();
2988 test_QueryFullProcessImageNameA();
2989 test_QueryFullProcessImageNameW();
2991 test_IsWow64Process();
2993 test_RegistryQuota();
2994 test_DuplicateHandle();
2995 test_StartupNoConsole();
2996 test_GetNumaProcessorNode();
2997 /* things that can be tested:
2998 * lookup: check the way program to be executed is searched
2999 * handles: check the handle inheritance stuff (+sec options)
3000 * console: check if console creation parameters work
3003 if (!pCreateJobObjectW
)
3005 win_skip("No job object support\n");
3009 test_IsProcessInJob();
3010 test_TerminateJobObject();
3011 test_QueryInformationJobObject();
3012 test_CompletionPort();
3013 test_KillOnJobClose();
3014 test_WaitForJobObject();
3015 job
= test_AddSelfToJob();
3016 test_jobInheritance(job
);
3017 test_BreakawayOk(job
);