2 * Unit test suite for process functions
4 * Copyright 2002 Eric Pouech
5 * Copyright 2006 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #define WIN32_NO_STATUS
36 #include "wine/test.h"
38 /* PROCESS_ALL_ACCESS in Vista+ PSDKs is incompatible with older Windows versions */
39 #define PROCESS_ALL_ACCESS_NT4 (PROCESS_ALL_ACCESS & ~0xf000)
41 #define expect_eq_d(expected, actual) \
43 int value = (actual); \
44 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
47 #define expect_eq_s(expected, actual) \
49 LPCSTR value = (actual); \
50 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
53 #define expect_eq_ws_i(expected, actual) \
55 LPCWSTR value = (actual); \
56 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
57 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
60 static HINSTANCE hkernel32
, hntdll
;
61 static void (WINAPI
*pGetNativeSystemInfo
)(LPSYSTEM_INFO
);
62 static BOOL (WINAPI
*pGetSystemRegistryQuota
)(PDWORD
, PDWORD
);
63 static BOOL (WINAPI
*pIsWow64Process
)(HANDLE
,PBOOL
);
64 static LPVOID (WINAPI
*pVirtualAllocEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
, DWORD
);
65 static BOOL (WINAPI
*pVirtualFreeEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
);
66 static BOOL (WINAPI
*pQueryFullProcessImageNameA
)(HANDLE hProcess
, DWORD dwFlags
, LPSTR lpExeName
, PDWORD lpdwSize
);
67 static BOOL (WINAPI
*pQueryFullProcessImageNameW
)(HANDLE hProcess
, DWORD dwFlags
, LPWSTR lpExeName
, PDWORD lpdwSize
);
68 static DWORD (WINAPI
*pK32GetProcessImageFileNameA
)(HANDLE
,LPSTR
,DWORD
);
69 static struct _TEB
* (WINAPI
*pNtCurrentTeb
)(void);
70 static HANDLE (WINAPI
*pCreateJobObjectW
)(LPSECURITY_ATTRIBUTES sa
, LPCWSTR name
);
71 static BOOL (WINAPI
*pAssignProcessToJobObject
)(HANDLE job
, HANDLE process
);
72 static BOOL (WINAPI
*pIsProcessInJob
)(HANDLE process
, HANDLE job
, PBOOL result
);
73 static BOOL (WINAPI
*pTerminateJobObject
)(HANDLE job
, UINT exit_code
);
74 static BOOL (WINAPI
*pQueryInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
, LPDWORD ret_len
);
75 static BOOL (WINAPI
*pSetInformationJobObject
)(HANDLE job
, JOBOBJECTINFOCLASS
class, LPVOID info
, DWORD len
);
76 static HANDLE (WINAPI
*pCreateIoCompletionPort
)(HANDLE file
, HANDLE existing_port
, ULONG_PTR key
, DWORD threads
);
78 /* ############################### */
79 static char base
[MAX_PATH
];
80 static char selfname
[MAX_PATH
];
82 static char resfile
[MAX_PATH
];
87 /* As some environment variables get very long on Unix, we only test for
88 * the first 127 bytes.
89 * Note that increasing this value past 256 may exceed the buffer size
90 * limitations of the *Profile functions (at least on Wine).
92 #define MAX_LISTED_ENV_VAR 128
94 /* ---------------- portable memory allocation thingie */
96 static char memory
[1024*256];
97 static char* memory_index
= memory
;
99 static char* grab_memory(size_t len
)
101 char* ret
= memory_index
;
103 len
= (len
+ 3) & ~3;
105 assert(memory_index
<= memory
+ sizeof(memory
));
109 static void release_memory(void)
111 memory_index
= memory
;
114 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
116 static const char* encodeA(const char* str
)
122 len
= strlen(str
) + 1;
123 ptr
= grab_memory(len
* 2 + 1);
124 for (i
= 0; i
< len
; i
++)
125 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
130 static const char* encodeW(const WCHAR
* str
)
136 len
= lstrlenW(str
) + 1;
137 ptr
= grab_memory(len
* 4 + 1);
139 for (i
= 0; i
< len
; i
++)
140 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
145 static unsigned decode_char(char c
)
147 if (c
>= '0' && c
<= '9') return c
- '0';
148 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
149 assert(c
>= 'A' && c
<= 'F');
153 static char* decodeA(const char* str
)
158 len
= strlen(str
) / 2;
159 if (!len
--) return NULL
;
160 ptr
= grab_memory(len
+ 1);
161 for (i
= 0; i
< len
; i
++)
162 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
167 /* This will be needed to decode Unicode strings saved by the child process
168 * when we test Unicode functions.
170 static WCHAR
* decodeW(const char* str
)
176 len
= strlen(str
) / 4;
177 if (!len
--) return NULL
;
178 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
179 for (i
= 0; i
< len
; i
++)
180 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
181 (decode_char(str
[4 * i
+ 1]) << 8) |
182 (decode_char(str
[4 * i
+ 2]) << 4) |
183 (decode_char(str
[4 * i
+ 3]) << 0);
188 /******************************************************************
191 * generates basic information like:
192 * base: absolute path to curr dir
193 * selfname: the way to reinvoke ourselves
194 * exename: executable without the path
195 * function-pointers, which are not implemented in all windows versions
197 static BOOL
init(void)
201 myARGC
= winetest_get_mainargs( &myARGV
);
202 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return FALSE
;
203 strcpy(selfname
, myARGV
[0]);
205 /* Strip the path of selfname */
206 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
207 else exename
= selfname
;
209 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
211 hkernel32
= GetModuleHandleA("kernel32");
212 hntdll
= GetModuleHandleA("ntdll.dll");
214 pGetNativeSystemInfo
= (void *) GetProcAddress(hkernel32
, "GetNativeSystemInfo");
215 pGetSystemRegistryQuota
= (void *) GetProcAddress(hkernel32
, "GetSystemRegistryQuota");
216 pIsWow64Process
= (void *) GetProcAddress(hkernel32
, "IsWow64Process");
217 pVirtualAllocEx
= (void *) GetProcAddress(hkernel32
, "VirtualAllocEx");
218 pVirtualFreeEx
= (void *) GetProcAddress(hkernel32
, "VirtualFreeEx");
219 pQueryFullProcessImageNameA
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameA");
220 pQueryFullProcessImageNameW
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameW");
221 pK32GetProcessImageFileNameA
= (void *) GetProcAddress(hkernel32
, "K32GetProcessImageFileNameA");
222 pNtCurrentTeb
= (void *)GetProcAddress(hntdll
, "NtCurrentTeb");
223 pCreateJobObjectW
= (void *)GetProcAddress(hkernel32
, "CreateJobObjectW");
224 pAssignProcessToJobObject
= (void *)GetProcAddress(hkernel32
, "AssignProcessToJobObject");
225 pIsProcessInJob
= (void *)GetProcAddress(hkernel32
, "IsProcessInJob");
226 pTerminateJobObject
= (void *)GetProcAddress(hkernel32
, "TerminateJobObject");
227 pQueryInformationJobObject
= (void *)GetProcAddress(hkernel32
, "QueryInformationJobObject");
228 pSetInformationJobObject
= (void *)GetProcAddress(hkernel32
, "SetInformationJobObject");
229 pCreateIoCompletionPort
= (void *)GetProcAddress(hkernel32
, "CreateIoCompletionPort");
233 /******************************************************************
236 * generates an absolute file_name for temporary file
239 static void get_file_name(char* buf
)
244 GetTempPathA(sizeof(path
), path
);
245 GetTempFileNameA(path
, "wt", 0, buf
);
248 /******************************************************************
249 * static void childPrintf
252 static void childPrintf(HANDLE h
, const char* fmt
, ...)
255 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
258 va_start(valist
, fmt
);
259 vsprintf(buffer
, fmt
, valist
);
261 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
265 /******************************************************************
268 * output most of the information in the child process
270 static void doChild(const char* file
, const char* option
)
275 char *ptrA
, *ptrA_save
;
276 WCHAR
*ptrW
, *ptrW_save
;
278 WCHAR bufW
[MAX_PATH
];
279 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
282 if (hFile
== INVALID_HANDLE_VALUE
) return;
284 /* output of startup info (Ansi) */
285 GetStartupInfoA(&siA
);
287 "[StartupInfoA]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
288 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
289 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
290 "dwFlags=%lu\nwShowWindow=%u\n"
291 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
292 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
293 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
294 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
295 siA
.dwFlags
, siA
.wShowWindow
,
296 (DWORD_PTR
)siA
.hStdInput
, (DWORD_PTR
)siA
.hStdOutput
, (DWORD_PTR
)siA
.hStdError
);
300 RTL_USER_PROCESS_PARAMETERS
*params
= pNtCurrentTeb()->Peb
->ProcessParameters
;
302 /* check the console handles in the TEB */
303 childPrintf(hFile
, "[TEB]\nhStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
304 (DWORD_PTR
)params
->hStdInput
, (DWORD_PTR
)params
->hStdOutput
,
305 (DWORD_PTR
)params
->hStdError
);
308 /* since GetStartupInfoW is only implemented in win2k,
309 * zero out before calling so we can notice the difference
311 memset(&siW
, 0, sizeof(siW
));
312 GetStartupInfoW(&siW
);
314 "[StartupInfoW]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
315 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
316 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
317 "dwFlags=%lu\nwShowWindow=%u\n"
318 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
319 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
320 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
321 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
322 siW
.dwFlags
, siW
.wShowWindow
,
323 (DWORD_PTR
)siW
.hStdInput
, (DWORD_PTR
)siW
.hStdOutput
, (DWORD_PTR
)siW
.hStdError
);
326 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
327 for (i
= 0; i
< myARGC
; i
++)
329 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
331 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
332 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
334 /* output of environment (Ansi) */
335 ptrA_save
= ptrA
= GetEnvironmentStringsA();
338 char env_var
[MAX_LISTED_ENV_VAR
];
340 childPrintf(hFile
, "[EnvironmentA]\n");
344 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
345 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
347 ptrA
+= strlen(ptrA
) + 1;
349 childPrintf(hFile
, "len=%d\n\n", i
);
350 FreeEnvironmentStringsA(ptrA_save
);
353 /* output of environment (Unicode) */
354 ptrW_save
= ptrW
= GetEnvironmentStringsW();
357 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
359 childPrintf(hFile
, "[EnvironmentW]\n");
363 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
364 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
365 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
367 ptrW
+= lstrlenW(ptrW
) + 1;
369 childPrintf(hFile
, "len=%d\n\n", i
);
370 FreeEnvironmentStringsW(ptrW_save
);
373 childPrintf(hFile
, "[Misc]\n");
374 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
375 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
376 if (GetCurrentDirectoryW(sizeof(bufW
) / sizeof(bufW
[0]), bufW
))
377 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
378 childPrintf(hFile
, "\n");
380 if (option
&& strcmp(option
, "console") == 0)
382 CONSOLE_SCREEN_BUFFER_INFO sbi
;
383 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
384 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
385 DWORD modeIn
, modeOut
;
387 childPrintf(hFile
, "[Console]\n");
388 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
390 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
391 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
392 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
393 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
394 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
395 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
397 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
398 GetConsoleCP(), GetConsoleOutputCP());
399 if (GetConsoleMode(hConIn
, &modeIn
))
400 childPrintf(hFile
, "InputMode=%ld\n", modeIn
);
401 if (GetConsoleMode(hConOut
, &modeOut
))
402 childPrintf(hFile
, "OutputMode=%ld\n", modeOut
);
404 /* now that we have written all relevant information, let's change it */
405 SetLastError(0xdeadbeef);
406 ret
= SetConsoleCP(1252);
407 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
409 win_skip("Setting the codepage is not implemented\n");
413 ok(ret
, "Setting CP\n");
414 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
417 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
418 ok( ret
, "Setting mode (%d)\n", GetLastError());
419 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
420 ok( ret
, "Setting mode (%d)\n", GetLastError());
421 sbi
.dwCursorPosition
.X
^= 1;
422 sbi
.dwCursorPosition
.Y
^= 1;
423 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
424 ok( ret
, "Setting cursor position (%d)\n", GetLastError());
426 if (option
&& strcmp(option
, "stdhandle") == 0)
428 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
429 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
431 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
436 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
437 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
438 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
442 if (option
&& strcmp(option
, "exit_code") == 0)
444 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
452 static char* getChildString(const char* sect
, const char* key
)
454 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
457 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
458 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
459 assert(!(strlen(buf
) & 1));
464 static WCHAR
* getChildStringW(const char* sect
, const char* key
)
466 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
469 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
470 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
471 assert(!(strlen(buf
) & 1));
476 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
477 * others... (windows uses stricmp while Un*x uses strcasecmp...)
479 static int wtstrcasecmp(const char* p1
, const char* p2
)
484 while (c1
== c2
&& c1
)
486 c1
= *p1
++; c2
= *p2
++;
489 c1
= toupper(c1
); c2
= toupper(c2
);
495 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
497 if (!s1
&& !s2
) return 0;
500 return (sensitive
) ? strcmp(s1
, s2
) : wtstrcasecmp(s1
, s2
);
503 static void ok_child_string( int line
, const char *sect
, const char *key
,
504 const char *expect
, int sensitive
)
506 char* result
= getChildString( sect
, key
);
507 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
508 sect
, key
, expect
? expect
: "(null)", result
);
511 static void ok_child_stringWA( int line
, const char *sect
, const char *key
,
512 const char *expect
, int sensitive
)
517 WCHAR
* result
= getChildStringW( sect
, key
);
519 len
= MultiByteToWideChar( CP_ACP
, 0, expect
, -1, NULL
, 0);
520 expectW
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
521 MultiByteToWideChar( CP_ACP
, 0, expect
, -1, expectW
, len
);
523 len
= WideCharToMultiByte( CP_ACP
, 0, result
, -1, NULL
, 0, NULL
, NULL
);
524 resultA
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(CHAR
));
525 WideCharToMultiByte( CP_ACP
, 0, result
, -1, resultA
, len
, NULL
, NULL
);
528 ok_(__FILE__
, line
)( lstrcmpW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
529 sect
, key
, expect
? expect
: "(null)", resultA
);
531 ok_(__FILE__
, line
)( lstrcmpiW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
532 sect
, key
, expect
? expect
: "(null)", resultA
);
533 HeapFree(GetProcessHeap(),0,expectW
);
534 HeapFree(GetProcessHeap(),0,resultA
);
537 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
538 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
539 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
541 /* using !expect ensures that the test will fail if the sect/key isn't present
544 #define okChildInt(sect, key, expect) \
546 UINT result = GetPrivateProfileIntA((sect), (key), !(expect), resfile); \
547 ok(result == expect, "%s:%s expected %u, but got %u\n", (sect), (key), (UINT)(expect), result); \
550 static void test_Startup(void)
552 char buffer
[MAX_PATH
];
553 PROCESS_INFORMATION info
;
554 STARTUPINFOA startup
,si
;
556 static CHAR title
[] = "I'm the title string",
557 desktop
[] = "winsta0\\default",
560 /* let's start simplistic */
561 memset(&startup
, 0, sizeof(startup
));
562 startup
.cb
= sizeof(startup
);
563 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
564 startup
.wShowWindow
= SW_SHOWNORMAL
;
566 get_file_name(resfile
);
567 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
568 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
569 /* wait for child to terminate */
570 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
571 /* child process has changed result file, so let profile functions know about it */
572 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
574 GetStartupInfoA(&si
);
575 okChildInt("StartupInfoA", "cb", startup
.cb
);
576 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
577 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
578 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
579 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
580 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
581 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
582 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
583 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
584 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
585 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
587 assert(DeleteFileA(resfile
) != 0);
589 /* not so simplistic now */
590 memset(&startup
, 0, sizeof(startup
));
591 startup
.cb
= sizeof(startup
);
592 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
593 startup
.wShowWindow
= SW_SHOWNORMAL
;
594 startup
.lpTitle
= title
;
595 startup
.lpDesktop
= desktop
;
596 startup
.dwXCountChars
= 0x12121212;
597 startup
.dwYCountChars
= 0x23232323;
598 startup
.dwX
= 0x34343434;
599 startup
.dwY
= 0x45454545;
600 startup
.dwXSize
= 0x56565656;
601 startup
.dwYSize
= 0x67676767;
602 startup
.dwFillAttribute
= 0xA55A;
604 get_file_name(resfile
);
605 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
606 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
607 /* wait for child to terminate */
608 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
609 /* child process has changed result file, so let profile functions know about it */
610 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
612 okChildInt("StartupInfoA", "cb", startup
.cb
);
613 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
614 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
615 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
616 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
617 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
618 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
619 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
620 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
621 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
622 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
623 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
625 assert(DeleteFileA(resfile
) != 0);
627 /* not so simplistic now */
628 memset(&startup
, 0, sizeof(startup
));
629 startup
.cb
= sizeof(startup
);
630 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
631 startup
.wShowWindow
= SW_SHOWNORMAL
;
632 startup
.lpTitle
= title
;
633 startup
.lpDesktop
= NULL
;
634 startup
.dwXCountChars
= 0x12121212;
635 startup
.dwYCountChars
= 0x23232323;
636 startup
.dwX
= 0x34343434;
637 startup
.dwY
= 0x45454545;
638 startup
.dwXSize
= 0x56565656;
639 startup
.dwYSize
= 0x67676767;
640 startup
.dwFillAttribute
= 0xA55A;
642 get_file_name(resfile
);
643 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
644 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
645 /* wait for child to terminate */
646 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
647 /* child process has changed result file, so let profile functions know about it */
648 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
650 okChildInt("StartupInfoA", "cb", startup
.cb
);
651 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
652 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
653 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
654 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
655 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
656 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
657 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
658 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
659 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
660 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
661 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
663 assert(DeleteFileA(resfile
) != 0);
665 /* not so simplistic now */
666 memset(&startup
, 0, sizeof(startup
));
667 startup
.cb
= sizeof(startup
);
668 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
669 startup
.wShowWindow
= SW_SHOWNORMAL
;
670 startup
.lpTitle
= title
;
671 startup
.lpDesktop
= empty
;
672 startup
.dwXCountChars
= 0x12121212;
673 startup
.dwYCountChars
= 0x23232323;
674 startup
.dwX
= 0x34343434;
675 startup
.dwY
= 0x45454545;
676 startup
.dwXSize
= 0x56565656;
677 startup
.dwYSize
= 0x67676767;
678 startup
.dwFillAttribute
= 0xA55A;
680 get_file_name(resfile
);
681 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
682 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
683 /* wait for child to terminate */
684 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
685 /* child process has changed result file, so let profile functions know about it */
686 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
688 okChildInt("StartupInfoA", "cb", startup
.cb
);
689 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
690 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
691 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
692 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
693 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
694 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
695 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
696 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
697 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
698 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
699 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
701 assert(DeleteFileA(resfile
) != 0);
703 /* not so simplistic now */
704 memset(&startup
, 0, sizeof(startup
));
705 startup
.cb
= sizeof(startup
);
706 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
707 startup
.wShowWindow
= SW_SHOWNORMAL
;
708 startup
.lpTitle
= NULL
;
709 startup
.lpDesktop
= desktop
;
710 startup
.dwXCountChars
= 0x12121212;
711 startup
.dwYCountChars
= 0x23232323;
712 startup
.dwX
= 0x34343434;
713 startup
.dwY
= 0x45454545;
714 startup
.dwXSize
= 0x56565656;
715 startup
.dwYSize
= 0x67676767;
716 startup
.dwFillAttribute
= 0xA55A;
718 get_file_name(resfile
);
719 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
720 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
721 /* wait for child to terminate */
722 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
723 /* child process has changed result file, so let profile functions know about it */
724 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
726 okChildInt("StartupInfoA", "cb", startup
.cb
);
727 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
728 result
= getChildString( "StartupInfoA", "lpTitle" );
729 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
730 "expected '%s' or null, got '%s'\n", selfname
, result
);
731 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
732 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
733 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
734 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
735 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
736 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
737 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
738 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
739 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
741 assert(DeleteFileA(resfile
) != 0);
743 /* not so simplistic now */
744 memset(&startup
, 0, sizeof(startup
));
745 startup
.cb
= sizeof(startup
);
746 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
747 startup
.wShowWindow
= SW_SHOWNORMAL
;
748 startup
.lpTitle
= empty
;
749 startup
.lpDesktop
= desktop
;
750 startup
.dwXCountChars
= 0x12121212;
751 startup
.dwYCountChars
= 0x23232323;
752 startup
.dwX
= 0x34343434;
753 startup
.dwY
= 0x45454545;
754 startup
.dwXSize
= 0x56565656;
755 startup
.dwYSize
= 0x67676767;
756 startup
.dwFillAttribute
= 0xA55A;
758 get_file_name(resfile
);
759 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
760 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
761 /* wait for child to terminate */
762 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
763 /* child process has changed result file, so let profile functions know about it */
764 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
766 okChildInt("StartupInfoA", "cb", startup
.cb
);
767 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
768 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
769 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
770 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
771 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
772 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
773 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
774 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
775 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
776 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
777 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
779 assert(DeleteFileA(resfile
) != 0);
781 /* not so simplistic now */
782 memset(&startup
, 0, sizeof(startup
));
783 startup
.cb
= sizeof(startup
);
784 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
785 startup
.wShowWindow
= SW_SHOWNORMAL
;
786 startup
.lpTitle
= empty
;
787 startup
.lpDesktop
= empty
;
788 startup
.dwXCountChars
= 0x12121212;
789 startup
.dwYCountChars
= 0x23232323;
790 startup
.dwX
= 0x34343434;
791 startup
.dwY
= 0x45454545;
792 startup
.dwXSize
= 0x56565656;
793 startup
.dwYSize
= 0x67676767;
794 startup
.dwFillAttribute
= 0xA55A;
796 get_file_name(resfile
);
797 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
798 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
799 /* wait for child to terminate */
800 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
801 /* child process has changed result file, so let profile functions know about it */
802 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
804 okChildInt("StartupInfoA", "cb", startup
.cb
);
805 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
806 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
807 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
808 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
809 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
810 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
811 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
812 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
813 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
814 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
815 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
817 assert(DeleteFileA(resfile
) != 0);
819 /* TODO: test for A/W and W/A and W/W */
822 static void test_CommandLine(void)
824 char buffer
[MAX_PATH
], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
825 char buffer2
[MAX_PATH
];
826 PROCESS_INFORMATION info
;
827 STARTUPINFOA startup
;
830 memset(&startup
, 0, sizeof(startup
));
831 startup
.cb
= sizeof(startup
);
832 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
833 startup
.wShowWindow
= SW_SHOWNORMAL
;
836 get_file_name(resfile
);
837 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
838 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
839 /* wait for child to terminate */
840 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
841 /* child process has changed result file, so let profile functions know about it */
842 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
844 okChildInt("Arguments", "argcA", 5);
845 okChildString("Arguments", "argvA4", "C:\\Program Files\\my nice app.exe");
846 okChildString("Arguments", "argvA5", NULL
);
847 okChildString("Arguments", "CommandLineA", buffer
);
849 assert(DeleteFileA(resfile
) != 0);
851 memset(&startup
, 0, sizeof(startup
));
852 startup
.cb
= sizeof(startup
);
853 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
854 startup
.wShowWindow
= SW_SHOWNORMAL
;
857 get_file_name(resfile
);
858 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname
, resfile
);
859 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
860 /* wait for child to terminate */
861 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
862 /* child process has changed result file, so let profile functions know about it */
863 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
865 okChildInt("Arguments", "argcA", 7);
866 okChildString("Arguments", "argvA4", "a\"b\\");
867 okChildString("Arguments", "argvA5", "c\"");
868 okChildString("Arguments", "argvA6", "d");
869 okChildString("Arguments", "argvA7", NULL
);
870 okChildString("Arguments", "CommandLineA", buffer
);
872 assert(DeleteFileA(resfile
) != 0);
874 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
875 get_file_name(resfile
);
876 /* Use exename to avoid buffer containing things like 'C:' */
877 sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
878 SetLastError(0xdeadbeef);
879 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
880 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
881 /* wait for child to terminate */
882 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
883 /* child process has changed result file, so let profile functions know about it */
884 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
885 sprintf(buffer
, "./%s", exename
);
886 okChildString("Arguments", "argvA0", buffer
);
888 assert(DeleteFileA(resfile
) != 0);
890 get_file_name(resfile
);
891 /* Use exename to avoid buffer containing things like 'C:' */
892 sprintf(buffer
, ".\\%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
893 SetLastError(0xdeadbeef);
894 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
895 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
896 /* wait for child to terminate */
897 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
898 /* child process has changed result file, so let profile functions know about it */
899 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
900 sprintf(buffer
, ".\\%s", exename
);
901 okChildString("Arguments", "argvA0", buffer
);
903 assert(DeleteFileA(resfile
) != 0);
905 get_file_name(resfile
);
906 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
907 assert ( lpFilePart
!= 0);
908 *(lpFilePart
-1 ) = 0;
909 p
= strrchr(fullpath
, '\\');
910 /* Use exename to avoid buffer containing things like 'C:' */
911 if (p
) sprintf(buffer
, "..%s/%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", p
, exename
, resfile
);
912 else sprintf(buffer
, "./%s tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
913 SetLastError(0xdeadbeef);
914 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
915 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
916 /* wait for child to terminate */
917 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
918 /* child process has changed result file, so let profile functions know about it */
919 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
920 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
921 else sprintf(buffer
, "./%s", exename
);
922 okChildString("Arguments", "argvA0", buffer
);
924 assert(DeleteFileA(resfile
) != 0);
927 get_file_name(resfile
);
928 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
929 assert ( lpFilePart
!= 0);
930 *(lpFilePart
-1 ) = 0;
931 p
= strrchr(fullpath
, '\\');
932 /* Use exename to avoid buffer containing things like 'C:' */
933 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
934 else sprintf(buffer
, "./%s", exename
);
935 sprintf(buffer2
, "dummy tests/process.c dump \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile
);
936 SetLastError(0xdeadbeef);
937 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
938 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
939 /* wait for child to terminate */
940 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
941 /* child process has changed result file, so let profile functions know about it */
942 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
943 sprintf(buffer
, "tests/process.c dump %s", resfile
);
944 okChildString("Arguments", "argvA0", "dummy");
945 okChildString("Arguments", "CommandLineA", buffer2
);
946 okChildStringWA("Arguments", "CommandLineW", buffer2
);
948 assert(DeleteFileA(resfile
) != 0);
950 if (0) /* Test crashes on NT-based Windows. */
952 /* Test NULL application name and command line parameters. */
953 SetLastError(0xdeadbeef);
954 ret
= CreateProcessA(NULL
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
955 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
956 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
957 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
962 /* Test empty application name parameter. */
963 SetLastError(0xdeadbeef);
964 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
965 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
966 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
967 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
968 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
969 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
973 /* Test empty application name and command line parameters. */
974 SetLastError(0xdeadbeef);
975 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
976 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
977 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
978 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
979 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
980 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
982 /* Test empty command line parameter. */
983 SetLastError(0xdeadbeef);
984 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
985 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
986 ok(GetLastError() == ERROR_FILE_NOT_FOUND
||
987 GetLastError() == ERROR_PATH_NOT_FOUND
/* NT4 */ ||
988 GetLastError() == ERROR_BAD_PATHNAME
/* Win98 */ ||
989 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7 */,
990 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
992 strcpy(buffer
, "doesnotexist.exe");
993 strcpy(buffer2
, "does not exist.exe");
995 /* Test nonexistent application name. */
996 SetLastError(0xdeadbeef);
997 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
998 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
999 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1001 SetLastError(0xdeadbeef);
1002 ret
= CreateProcessA(buffer2
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1003 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1004 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1006 /* Test nonexistent command line parameter. */
1007 SetLastError(0xdeadbeef);
1008 ret
= CreateProcessA(NULL
, buffer
, 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 SetLastError(0xdeadbeef);
1013 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
1014 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
1015 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1018 static void test_Directory(void)
1020 char buffer
[MAX_PATH
];
1021 PROCESS_INFORMATION info
;
1022 STARTUPINFOA startup
;
1023 char windir
[MAX_PATH
];
1024 static CHAR cmdline
[] = "winver.exe";
1026 memset(&startup
, 0, sizeof(startup
));
1027 startup
.cb
= sizeof(startup
);
1028 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1029 startup
.wShowWindow
= SW_SHOWNORMAL
;
1032 get_file_name(resfile
);
1033 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1034 GetWindowsDirectoryA( windir
, sizeof(windir
) );
1035 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
1036 /* wait for child to terminate */
1037 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1038 /* child process has changed result file, so let profile functions know about it */
1039 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1041 okChildIString("Misc", "CurrDirA", windir
);
1043 assert(DeleteFileA(resfile
) != 0);
1045 /* search PATH for the exe if directory is NULL */
1046 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1047 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
1049 /* if any directory is provided, don't search PATH, error on bad directory */
1050 SetLastError(0xdeadbeef);
1051 memset(&info
, 0, sizeof(info
));
1052 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
1053 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
1054 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1055 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
1058 static BOOL
is_str_env_drive_dir(const char* str
)
1060 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1061 str
[3] == '=' && str
[4] == str
[1];
1064 /* compared expected child's environment (in gesA) from actual
1065 * environment our child got
1067 static void cmpEnvironment(const char* gesA
)
1075 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1077 /* now look each parent env in child */
1078 if ((ptrA
= gesA
) != NULL
)
1082 for (i
= 0; i
< clen
; i
++)
1084 sprintf(key
, "env%d", i
);
1085 res
= getChildString("EnvironmentA", key
);
1086 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1090 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1092 ptrA
+= strlen(ptrA
) + 1;
1096 /* and each child env in parent */
1097 for (i
= 0; i
< clen
; i
++)
1099 sprintf(key
, "env%d", i
);
1100 res
= getChildString("EnvironmentA", key
);
1101 if ((ptrA
= gesA
) != NULL
)
1105 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1107 ptrA
+= strlen(ptrA
) + 1;
1109 if (!*ptrA
) ptrA
= NULL
;
1112 if (!is_str_env_drive_dir(res
))
1114 found
= ptrA
!= NULL
;
1115 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1117 /* else => should also test we get the right per drive default directory here... */
1121 static void test_Environment(void)
1123 char buffer
[MAX_PATH
];
1124 PROCESS_INFORMATION info
;
1125 STARTUPINFOA startup
;
1133 memset(&startup
, 0, sizeof(startup
));
1134 startup
.cb
= sizeof(startup
);
1135 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1136 startup
.wShowWindow
= SW_SHOWNORMAL
;
1139 get_file_name(resfile
);
1140 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1141 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1142 /* wait for child to terminate */
1143 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1144 /* child process has changed result file, so let profile functions know about it */
1145 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1147 env
= GetEnvironmentStringsA();
1148 cmpEnvironment(env
);
1150 assert(DeleteFileA(resfile
) != 0);
1152 memset(&startup
, 0, sizeof(startup
));
1153 startup
.cb
= sizeof(startup
);
1154 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1155 startup
.wShowWindow
= SW_SHOWNORMAL
;
1158 get_file_name(resfile
);
1159 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1165 slen
= strlen(ptr
)+1;
1166 child_env_len
+= slen
;
1169 /* Add space for additional environment variables */
1170 child_env_len
+= 256;
1171 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1174 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1175 ptr
+= strlen(ptr
) + 1;
1176 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1177 ptr
+= strlen(ptr
) + 1;
1178 strcpy(ptr
, "FOO=BAR");
1179 ptr
+= strlen(ptr
) + 1;
1180 strcpy(ptr
, "BAR=FOOBAR");
1181 ptr
+= strlen(ptr
) + 1;
1182 /* copy all existing variables except:
1184 * - PATH (already set above)
1185 * - the directory definitions (=[A-Z]:=)
1187 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1189 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1190 strncmp(ptr2
, "WINELOADER=", 11) != 0 &&
1191 !is_str_env_drive_dir(ptr2
))
1194 ptr
+= strlen(ptr
) + 1;
1198 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1199 /* wait for child to terminate */
1200 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1201 /* child process has changed result file, so let profile functions know about it */
1202 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1204 cmpEnvironment(child_env
);
1206 HeapFree(GetProcessHeap(), 0, child_env
);
1207 FreeEnvironmentStringsA(env
);
1209 assert(DeleteFileA(resfile
) != 0);
1212 static void test_SuspendFlag(void)
1214 char buffer
[MAX_PATH
];
1215 PROCESS_INFORMATION info
;
1216 STARTUPINFOA startup
, us
;
1220 /* let's start simplistic */
1221 memset(&startup
, 0, sizeof(startup
));
1222 startup
.cb
= sizeof(startup
);
1223 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1224 startup
.wShowWindow
= SW_SHOWNORMAL
;
1226 get_file_name(resfile
);
1227 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1228 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1230 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1232 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1233 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1235 /* wait for child to terminate */
1236 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1237 /* child process has changed result file, so let profile functions know about it */
1238 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1240 GetStartupInfoA(&us
);
1242 okChildInt("StartupInfoA", "cb", startup
.cb
);
1243 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1244 result
= getChildString( "StartupInfoA", "lpTitle" );
1245 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1246 "expected '%s' or null, got '%s'\n", selfname
, result
);
1247 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1248 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1249 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1250 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1251 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1252 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1253 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1254 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1255 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1257 assert(DeleteFileA(resfile
) != 0);
1260 static void test_DebuggingFlag(void)
1262 char buffer
[MAX_PATH
];
1263 void *processbase
= NULL
;
1264 PROCESS_INFORMATION info
;
1265 STARTUPINFOA startup
, us
;
1270 /* let's start simplistic */
1271 memset(&startup
, 0, sizeof(startup
));
1272 startup
.cb
= sizeof(startup
);
1273 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1274 startup
.wShowWindow
= SW_SHOWNORMAL
;
1276 get_file_name(resfile
);
1277 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
1278 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1280 /* get all startup events up to the entry point break exception */
1283 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1284 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1287 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1288 "first event: %d\n", de
.dwDebugEventCode
);
1289 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1291 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1292 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1293 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1294 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1296 ok(dbg
, "I have seen a debug event\n");
1297 /* wait for child to terminate */
1298 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1299 /* child process has changed result file, so let profile functions know about it */
1300 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1302 GetStartupInfoA(&us
);
1304 okChildInt("StartupInfoA", "cb", startup
.cb
);
1305 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1306 result
= getChildString( "StartupInfoA", "lpTitle" );
1307 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1308 "expected '%s' or null, got '%s'\n", selfname
, result
);
1309 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1310 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1311 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1312 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1313 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1314 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1315 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1316 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1317 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1319 assert(DeleteFileA(resfile
) != 0);
1322 static BOOL
is_console(HANDLE h
)
1324 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1327 static void test_Console(void)
1329 char buffer
[MAX_PATH
];
1330 PROCESS_INFORMATION info
;
1331 STARTUPINFOA startup
, us
;
1332 SECURITY_ATTRIBUTES sa
;
1333 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1334 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1335 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1337 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1338 const char* msg
= "This is a std-handle inheritance test.";
1340 BOOL run_tests
= TRUE
;
1343 memset(&startup
, 0, sizeof(startup
));
1344 startup
.cb
= sizeof(startup
);
1345 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1346 startup
.wShowWindow
= SW_SHOWNORMAL
;
1348 sa
.nLength
= sizeof(sa
);
1349 sa
.lpSecurityDescriptor
= NULL
;
1350 sa
.bInheritHandle
= TRUE
;
1352 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1353 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1355 /* first, we need to be sure we're attached to a console */
1356 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1358 /* we're not attached to a console, let's do it */
1360 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1361 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1363 /* now verify everything's ok */
1364 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1365 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1366 startup
.hStdError
= startup
.hStdOutput
;
1368 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1369 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
) &&
1370 GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console modes\n");
1371 cpIn
= GetConsoleCP();
1372 cpOut
= GetConsoleOutputCP();
1374 get_file_name(resfile
);
1375 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" console", selfname
, resfile
);
1376 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1378 /* wait for child to terminate */
1379 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1380 /* child process has changed result file, so let profile functions know about it */
1381 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1383 /* now get the modification the child has made, and resets parents expected values */
1384 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1385 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
) &&
1386 GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console modes\n");
1388 SetConsoleMode(startup
.hStdInput
, modeIn
);
1389 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1391 cpInC
= GetConsoleCP();
1392 cpOutC
= GetConsoleOutputCP();
1394 /* Try to set invalid CP */
1395 SetLastError(0xdeadbeef);
1396 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1397 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1398 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1399 "GetLastError: expecting %u got %u\n",
1400 ERROR_INVALID_PARAMETER
, GetLastError());
1401 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1405 SetLastError(0xdeadbeef);
1406 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1407 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1408 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1409 "GetLastError: expecting %u got %u\n",
1410 ERROR_INVALID_PARAMETER
, GetLastError());
1413 SetConsoleOutputCP(cpOut
);
1415 GetStartupInfoA(&us
);
1417 okChildInt("StartupInfoA", "cb", startup
.cb
);
1418 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1419 result
= getChildString( "StartupInfoA", "lpTitle" );
1420 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1421 "expected '%s' or null, got '%s'\n", selfname
, result
);
1422 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1423 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1424 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1425 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1426 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1427 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1428 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1429 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1430 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1432 /* check child correctly inherited the console */
1433 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1434 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1435 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1436 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1437 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1438 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1439 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1440 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1441 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1442 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1443 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1444 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1445 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1446 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1447 okChildInt("Console", "InputCP", cpIn
);
1448 okChildInt("Console", "OutputCP", cpOut
);
1449 okChildInt("Console", "InputMode", modeIn
);
1450 okChildInt("Console", "OutputMode", modeOut
);
1454 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1455 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1458 win_skip("Setting the codepage is not implemented\n");
1460 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1461 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1462 trace("cursor position(X): %d/%d\n",sbi
.dwCursorPosition
.X
, sbiC
.dwCursorPosition
.X
);
1463 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1466 assert(DeleteFileA(resfile
) != 0);
1468 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1469 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1470 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1471 "Duplicating as inheritable child-output pipe\n");
1472 CloseHandle(hChildOut
);
1474 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1475 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1476 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1477 "Duplicating as inheritable child-input pipe\n");
1478 CloseHandle(hChildIn
);
1480 memset(&startup
, 0, sizeof(startup
));
1481 startup
.cb
= sizeof(startup
);
1482 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1483 startup
.wShowWindow
= SW_SHOWNORMAL
;
1484 startup
.hStdInput
= hChildInInh
;
1485 startup
.hStdOutput
= hChildOutInh
;
1486 startup
.hStdError
= hChildOutInh
;
1488 get_file_name(resfile
);
1489 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" stdhandle", selfname
, resfile
);
1490 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1491 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1492 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1494 msg_len
= strlen(msg
) + 1;
1495 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1496 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1497 memset(buffer
, 0, sizeof(buffer
));
1498 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1499 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1501 /* wait for child to terminate */
1502 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1503 /* child process has changed result file, so let profile functions know about it */
1504 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1506 okChildString("StdHandle", "msg", msg
);
1509 assert(DeleteFileA(resfile
) != 0);
1512 static void test_ExitCode(void)
1514 char buffer
[MAX_PATH
];
1515 PROCESS_INFORMATION info
;
1516 STARTUPINFOA startup
;
1519 /* let's start simplistic */
1520 memset(&startup
, 0, sizeof(startup
));
1521 startup
.cb
= sizeof(startup
);
1522 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1523 startup
.wShowWindow
= SW_SHOWNORMAL
;
1525 get_file_name(resfile
);
1526 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\" exit_code", selfname
, resfile
);
1527 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1529 /* wait for child to terminate */
1530 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1531 /* child process has changed result file, so let profile functions know about it */
1532 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1534 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1535 okChildInt("ExitCode", "value", code
);
1538 assert(DeleteFileA(resfile
) != 0);
1541 static void test_OpenProcess(void)
1545 MEMORY_BASIC_INFORMATION info
;
1546 SIZE_T dummy
, read_bytes
;
1549 /* not exported in all windows versions */
1550 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1551 win_skip("VirtualAllocEx not found\n");
1555 /* without PROCESS_VM_OPERATION */
1556 hproc
= OpenProcess(PROCESS_ALL_ACCESS_NT4
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1557 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1559 SetLastError(0xdeadbeef);
1560 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1561 ok(!addr1
, "VirtualAllocEx should fail\n");
1562 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1565 win_skip("VirtualAllocEx not implemented\n");
1568 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1570 read_bytes
= 0xdeadbeef;
1571 SetLastError(0xdeadbeef);
1572 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1573 ok(ret
, "ReadProcessMemory error %d\n", GetLastError());
1574 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1578 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1579 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1581 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1582 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1584 /* without PROCESS_QUERY_INFORMATION */
1585 SetLastError(0xdeadbeef);
1586 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1587 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1588 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1590 /* without PROCESS_VM_READ */
1591 read_bytes
= 0xdeadbeef;
1592 SetLastError(0xdeadbeef);
1593 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1594 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1595 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1596 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1600 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1602 memset(&info
, 0xcc, sizeof(info
));
1603 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1604 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1606 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1607 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1608 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1609 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1610 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1611 /* NT reports Protect == 0 for a not committed memory block */
1612 ok(info
.Protect
== 0 /* NT */ ||
1613 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1614 "%x != PAGE_NOACCESS\n", info
.Protect
);
1615 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1617 SetLastError(0xdeadbeef);
1618 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1619 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1620 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1624 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1627 static void test_GetProcessVersion(void)
1629 static char cmdline
[] = "winver.exe";
1630 PROCESS_INFORMATION pi
;
1634 SetLastError(0xdeadbeef);
1635 ret
= GetProcessVersion(0);
1636 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1638 SetLastError(0xdeadbeef);
1639 ret
= GetProcessVersion(GetCurrentProcessId());
1640 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1642 memset(&si
, 0, sizeof(si
));
1644 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1645 si
.wShowWindow
= SW_HIDE
;
1646 SetLastError(0xdeadbeef);
1647 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1648 ok(ret
, "CreateProcess error %u\n", GetLastError());
1650 SetLastError(0xdeadbeef);
1651 ret
= GetProcessVersion(pi
.dwProcessId
);
1652 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1654 SetLastError(0xdeadbeef);
1655 ret
= TerminateProcess(pi
.hProcess
, 0);
1656 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1658 CloseHandle(pi
.hProcess
);
1659 CloseHandle(pi
.hThread
);
1662 static void test_GetProcessImageFileNameA(void)
1665 CHAR process
[MAX_PATH
];
1666 static const char harddisk
[] = "\\Device\\HarddiskVolume";
1668 if (!pK32GetProcessImageFileNameA
)
1670 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1674 /* callers must guess the buffer size */
1675 SetLastError(0xdeadbeef);
1676 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL
, 0);
1677 ok(!rc
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
1678 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc
, GetLastError());
1681 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), process
, sizeof(process
));
1682 expect_eq_d(rc
, lstrlenA(process
));
1683 if (strncmp(process
, harddisk
, lstrlenA(harddisk
)))
1685 todo_wine
win_skip("%s is probably on a network share, skipping tests\n", process
);
1689 if (!pQueryFullProcessImageNameA
)
1690 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1693 CHAR image
[MAX_PATH
];
1696 length
= sizeof(image
);
1697 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE
, image
, &length
));
1698 expect_eq_d(length
, lstrlenA(image
));
1699 ok(lstrcmpiA(process
, image
) == 0, "expected '%s' to be equal to '%s'\n", process
, image
);
1703 static void test_QueryFullProcessImageNameA(void)
1705 #define INIT_STR "Just some words"
1707 CHAR buf
[MAX_PATH
], module
[MAX_PATH
];
1709 if (!pQueryFullProcessImageNameA
)
1711 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1716 SetLastError(0); /* old Windows don't reset it on success */
1717 size
= GetModuleFileNameA(NULL
, module
, sizeof(module
));
1718 ok(size
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
, "GetModuleFileName failed: %u le=%u\n", size
, GetLastError());
1720 /* get the buffer length without \0 terminator */
1721 length
= sizeof(buf
);
1722 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1723 expect_eq_d(length
, lstrlenA(buf
));
1724 ok((buf
[0] == '\\' && buf
[1] == '\\') ||
1725 lstrcmpiA(buf
, module
) == 0, "expected %s to match %s\n", buf
, module
);
1727 /* when the buffer is too small
1728 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1729 * - the size variable is not modified
1730 * tested with the biggest too small size
1733 sprintf(buf
,INIT_STR
);
1734 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1735 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1736 expect_eq_d(length
, size
);
1737 expect_eq_s(INIT_STR
, buf
);
1739 /* retest with smaller buffer size
1742 sprintf(buf
,INIT_STR
);
1743 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1744 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1745 expect_eq_d(4, size
);
1746 expect_eq_s(INIT_STR
, buf
);
1748 /* this is a difference between the ascii and the unicode version
1749 * the unicode version crashes when the size is big enough to hold
1750 * the result while the ascii version throws an error
1753 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1754 expect_eq_d(1024, size
);
1755 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1758 static void test_QueryFullProcessImageNameW(void)
1761 WCHAR module_name
[1024], device
[1024];
1762 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
1766 if (!pQueryFullProcessImageNameW
)
1768 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1772 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1774 /* GetCurrentProcess pseudo-handle */
1775 size
= sizeof(buf
) / sizeof(buf
[0]);
1776 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
1777 expect_eq_d(lstrlenW(buf
), size
);
1778 expect_eq_ws_i(buf
, module_name
);
1780 hSelf
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1782 size
= sizeof(buf
) / sizeof(buf
[0]);
1783 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1784 expect_eq_d(lstrlenW(buf
), size
);
1785 expect_eq_ws_i(buf
, module_name
);
1787 /* Buffer too small */
1788 size
= lstrlenW(module_name
)/2;
1789 lstrcpyW(buf
, deviceW
);
1790 SetLastError(0xdeadbeef);
1791 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1792 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1793 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1794 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
1796 /* Too small - not space for NUL terminator */
1797 size
= lstrlenW(module_name
);
1798 SetLastError(0xdeadbeef);
1799 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1800 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
1801 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1805 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
1806 expect_eq_d(0, size
);
1807 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1809 /* Buffer too small */
1810 size
= lstrlenW(module_name
)/2;
1811 SetLastError(0xdeadbeef);
1812 lstrcpyW(buf
, module_name
);
1813 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1814 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1815 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1816 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
1820 size
= sizeof(buf
) / sizeof(buf
[0]);
1821 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
1822 expect_eq_d(lstrlenW(buf
), size
);
1823 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
1824 ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
1826 module_name
[2] = '\0';
1828 size
= QueryDosDeviceW(module_name
, device
, sizeof(device
)/sizeof(device
[0]));
1829 ok(size
, "QueryDosDeviceW failed: le=%u\n", GetLastError());
1830 len
= lstrlenW(device
);
1831 ok(size
>= len
+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size
, len
, wine_dbgstr_w(device
));
1833 if (size
>= lstrlenW(buf
))
1835 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
1839 ok(buf
[len
] == '\\', "expected '%c' to be a '\\' in %s\n", buf
[len
], wine_dbgstr_w(module_name
));
1841 ok(lstrcmpiW(device
, buf
) == 0, "expected %s to match %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
1842 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));
1848 static void test_Handles(void)
1850 HANDLE handle
= GetCurrentProcess();
1855 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
1856 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
1857 "invalid current process handle %p\n", handle
);
1858 ret
= GetExitCodeProcess( handle
, &code
);
1859 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1861 /* truncated handle */
1862 SetLastError( 0xdeadbeef );
1863 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
1864 ret
= GetExitCodeProcess( handle
, &code
);
1865 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1866 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1867 /* sign-extended handle */
1868 SetLastError( 0xdeadbeef );
1869 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
1870 ret
= GetExitCodeProcess( handle
, &code
);
1871 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1872 /* invalid high-word */
1873 SetLastError( 0xdeadbeef );
1874 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
1875 ret
= GetExitCodeProcess( handle
, &code
);
1876 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1877 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1880 handle
= GetStdHandle( STD_ERROR_HANDLE
);
1881 ok( handle
!= 0, "handle %p\n", handle
);
1882 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
1883 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1884 SetStdHandle( STD_ERROR_HANDLE
, h3
);
1885 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
1886 h2
= GetStdHandle( STD_ERROR_HANDLE
);
1888 broken( h2
== h3
) || /* nt4, w2k */
1889 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
1890 "wrong handle %p/%p\n", h2
, h3
);
1891 SetStdHandle( STD_ERROR_HANDLE
, handle
);
1894 static void test_IsWow64Process(void)
1896 PROCESS_INFORMATION pi
;
1900 static char cmdline
[] = "C:\\Program Files\\Internet Explorer\\iexplore.exe";
1901 static char cmdline_wow64
[] = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
1903 if (!pIsWow64Process
)
1905 skip("IsWow64Process is not available\n");
1909 memset(&si
, 0, sizeof(si
));
1911 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1912 si
.wShowWindow
= SW_HIDE
;
1913 ret
= CreateProcessA(NULL
, cmdline_wow64
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1916 trace("Created process %s\n", cmdline_wow64
);
1918 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
1919 ok(ret
, "IsWow64Process failed.\n");
1920 ok(is_wow64
, "is_wow64 returned FALSE.\n");
1922 ret
= TerminateProcess(pi
.hProcess
, 0);
1923 ok(ret
, "TerminateProcess error\n");
1925 CloseHandle(pi
.hProcess
);
1926 CloseHandle(pi
.hThread
);
1929 memset(&si
, 0, sizeof(si
));
1931 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1932 si
.wShowWindow
= SW_HIDE
;
1933 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1936 trace("Created process %s\n", cmdline
);
1938 ret
= pIsWow64Process(pi
.hProcess
, &is_wow64
);
1939 ok(ret
, "IsWow64Process failed.\n");
1940 ok(!is_wow64
, "is_wow64 returned TRUE.\n");
1942 ret
= TerminateProcess(pi
.hProcess
, 0);
1943 ok(ret
, "TerminateProcess error\n");
1945 CloseHandle(pi
.hProcess
);
1946 CloseHandle(pi
.hThread
);
1950 static void test_SystemInfo(void)
1952 SYSTEM_INFO si
, nsi
;
1955 if (!pGetNativeSystemInfo
)
1957 win_skip("GetNativeSystemInfo is not available\n");
1961 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
1964 pGetNativeSystemInfo(&nsi
);
1967 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
1969 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
1970 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
1971 S(U(nsi
)).wProcessorArchitecture
);
1972 ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
,
1973 "Expected PROCESSOR_AMD_X8664, got %d\n",
1974 nsi
.dwProcessorType
);
1979 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
1980 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
1981 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
1982 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
1983 "Expected no difference for dwProcessorType, got %d and %d\n",
1984 si
.dwProcessorType
, nsi
.dwProcessorType
);
1988 static void test_RegistryQuota(void)
1991 DWORD max_quota
, used_quota
;
1993 if (!pGetSystemRegistryQuota
)
1995 win_skip("GetSystemRegistryQuota is not available\n");
1999 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
2001 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2003 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
2005 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2007 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
2009 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2011 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
2013 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
2016 static void test_TerminateProcess(void)
2018 static char cmdline
[] = "winver.exe";
2019 PROCESS_INFORMATION pi
;
2022 HANDLE dummy
, thread
;
2024 memset(&si
, 0, sizeof(si
));
2026 SetLastError(0xdeadbeef);
2027 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
2028 ok(ret
, "CreateProcess error %u\n", GetLastError());
2030 SetLastError(0xdeadbeef);
2031 thread
= CreateRemoteThread(pi
.hProcess
, NULL
, 0, (void *)0xdeadbeef, NULL
, CREATE_SUSPENDED
, &ret
);
2032 ok(thread
!= 0, "CreateRemoteThread error %d\n", GetLastError());
2034 /* create a not closed thread handle duplicate in the target process */
2035 SetLastError(0xdeadbeef);
2036 ret
= DuplicateHandle(GetCurrentProcess(), thread
, pi
.hProcess
, &dummy
,
2037 0, FALSE
, DUPLICATE_SAME_ACCESS
);
2038 ok(ret
, "DuplicateHandle error %u\n", GetLastError());
2040 SetLastError(0xdeadbeef);
2041 ret
= TerminateThread(thread
, 0);
2042 ok(ret
, "TerminateThread error %u\n", GetLastError());
2043 CloseHandle(thread
);
2045 SetLastError(0xdeadbeef);
2046 ret
= TerminateProcess(pi
.hProcess
, 0);
2047 ok(ret
, "TerminateProcess error %u\n", GetLastError());
2049 CloseHandle(pi
.hProcess
);
2050 CloseHandle(pi
.hThread
);
2053 static void test_DuplicateHandle(void)
2055 char path
[MAX_PATH
], file_name
[MAX_PATH
];
2056 HANDLE f
, fmin
, out
;
2060 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2061 GetCurrentProcess(), &out
, 0, FALSE
,
2062 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2063 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2064 r
= GetHandleInformation(out
, &info
);
2065 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2066 ok(info
== 0, "info = %x\n", info
);
2067 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2070 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
2071 GetCurrentProcess(), &out
, 0, TRUE
,
2072 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2073 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2074 r
= GetHandleInformation(out
, &info
);
2075 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2076 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2077 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
2080 GetTempPathA(MAX_PATH
, path
);
2081 GetTempFileNameA(path
, "wt", 0, file_name
);
2082 f
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
2083 if (f
== INVALID_HANDLE_VALUE
)
2085 ok(0, "could not create %s\n", file_name
);
2089 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2090 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2091 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2092 ok(f
== out
, "f != out\n");
2093 r
= GetHandleInformation(out
, &info
);
2094 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2095 ok(info
== 0, "info = %x\n", info
);
2097 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2098 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2099 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2100 ok(f
== out
, "f != out\n");
2101 r
= GetHandleInformation(out
, &info
);
2102 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2103 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2105 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, HANDLE_FLAG_PROTECT_FROM_CLOSE
);
2106 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2107 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2108 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2109 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2110 ok(f
!= out
, "f == out\n");
2111 r
= GetHandleInformation(out
, &info
);
2112 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2113 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2114 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, 0);
2115 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2117 /* Test if DuplicateHandle allocates first free handle */
2128 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2129 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2130 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2131 ok(f
== out
, "f != out\n");
2133 DeleteFileA(file_name
);
2135 f
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2138 skip("DuplicateHandle on console handle\n");
2143 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2144 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2145 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2146 todo_wine
ok(f
!= out
, "f == out\n");
2150 #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e)
2151 static void _test_completion(int line
, HANDLE port
, DWORD ekey
, ULONG_PTR evalue
, ULONG_PTR eoverlapped
, DWORD wait
)
2153 LPOVERLAPPED overlapped
;
2158 ret
= GetQueuedCompletionStatus(port
, &key
, &value
, &overlapped
, wait
);
2160 ok_(__FILE__
, line
)(ret
, "GetQueuedCompletionStatus: %x\n", GetLastError());
2163 ok_(__FILE__
, line
)(key
== ekey
, "unexpected key %x\n", key
);
2164 ok_(__FILE__
, line
)(value
== evalue
, "unexpected value %p\n", (void *)value
);
2165 ok_(__FILE__
, line
)(overlapped
== (LPOVERLAPPED
)eoverlapped
, "unexpected overlapped %p\n", overlapped
);
2169 #define create_process(cmd, pi) _create_process(__LINE__, cmd, pi)
2170 static void _create_process(int line
, const char *command
, LPPROCESS_INFORMATION pi
)
2173 char buffer
[MAX_PATH
];
2174 STARTUPINFOA si
= {0};
2176 snprintf(buffer
, MAX_PATH
, "\"%s\" tests/process.c %s", selfname
, command
);
2178 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, pi
);
2179 ok_(__FILE__
, line
)(ret
, "CreateProcess error %u\n", GetLastError());
2183 static void test_IsProcessInJob(void)
2186 PROCESS_INFORMATION pi
;
2190 if (!pIsProcessInJob
)
2192 win_skip("IsProcessInJob not available.\n");
2196 job
= pCreateJobObjectW(NULL
, NULL
);
2197 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2199 job2
= pCreateJobObjectW(NULL
, NULL
);
2200 ok(job2
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2202 create_process("wait", &pi
);
2205 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2206 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2207 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2210 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2211 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2212 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2215 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2216 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2217 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2219 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2220 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2223 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2224 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2225 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2228 ret
= pIsProcessInJob(pi
.hProcess
, job2
, &out
);
2229 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2230 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2233 ret
= pIsProcessInJob(pi
.hProcess
, NULL
, &out
);
2234 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2235 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2237 TerminateProcess(pi
.hProcess
, 0);
2239 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2240 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2243 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2244 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2245 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2247 CloseHandle(pi
.hProcess
);
2248 CloseHandle(pi
.hThread
);
2253 static void test_TerminateJobObject(void)
2256 PROCESS_INFORMATION pi
;
2260 job
= pCreateJobObjectW(NULL
, NULL
);
2261 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2263 create_process("wait", &pi
);
2265 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2266 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2268 ret
= pTerminateJobObject(job
, 123);
2269 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2271 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2272 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2273 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2275 ret
= GetExitCodeProcess(pi
.hProcess
, &dwret
);
2276 ok(ret
, "GetExitCodeProcess error %u\n", GetLastError());
2277 ok(dwret
== 123 || broken(dwret
== 0) /* randomly fails on Win 2000 / XP */,
2278 "wrong exitcode %u\n", dwret
);
2280 CloseHandle(pi
.hProcess
);
2281 CloseHandle(pi
.hThread
);
2283 /* Test adding an already terminated process to a job object */
2284 create_process("exit", &pi
);
2286 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2287 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2289 SetLastError(0xdeadbeef);
2290 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2291 ok(!ret
, "AssignProcessToJobObject unexpectedly succeeded\n");
2292 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2294 CloseHandle(pi
.hProcess
);
2295 CloseHandle(pi
.hThread
);
2300 static void test_QueryInformationJobObject(void)
2302 char buf
[FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[5])];
2303 PJOBOBJECT_BASIC_PROCESS_ID_LIST pid_list
= (JOBOBJECT_BASIC_PROCESS_ID_LIST
*)buf
;
2304 DWORD dwret
, ret_len
;
2305 PROCESS_INFORMATION pi
[2];
2309 job
= pCreateJobObjectW(NULL
, NULL
);
2310 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2312 /* Only active processes are returned */
2313 create_process("exit", &pi
[0]);
2314 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2315 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2316 dwret
= WaitForSingleObject(pi
[0].hProcess
, 1000);
2317 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2319 CloseHandle(pi
[0].hProcess
);
2320 CloseHandle(pi
[0].hThread
);
2322 create_process("wait", &pi
[0]);
2323 ret
= pAssignProcessToJobObject(job
, pi
[0].hProcess
);
2324 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2326 create_process("wait", &pi
[1]);
2327 ret
= pAssignProcessToJobObject(job
, pi
[1].hProcess
);
2328 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2330 SetLastError(0xdeadbeef);
2331 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2332 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
), &ret_len
);
2333 ok(!ret
, "QueryInformationJobObject expected failure\n");
2335 expect_eq_d(ERROR_BAD_LENGTH
, GetLastError());
2337 SetLastError(0xdeadbeef);
2338 memset(buf
, 0, sizeof(buf
));
2339 pid_list
->NumberOfAssignedProcesses
= 42;
2340 pid_list
->NumberOfProcessIdsInList
= 42;
2341 ret
= QueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
,
2342 FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[1]), &ret_len
);
2343 ok(!ret
, "QueryInformationJobObject expected failure\n");
2345 expect_eq_d(ERROR_MORE_DATA
, GetLastError());
2348 expect_eq_d(42, pid_list
->NumberOfAssignedProcesses
);
2349 expect_eq_d(42, pid_list
->NumberOfProcessIdsInList
);
2352 memset(buf
, 0, sizeof(buf
));
2353 ret
= pQueryInformationJobObject(job
, JobObjectBasicProcessIdList
, pid_list
, sizeof(buf
), &ret_len
);
2355 ok(ret
, "QueryInformationJobObject error %u\n", GetLastError());
2358 if (pid_list
->NumberOfAssignedProcesses
== 3) /* Win 8 */
2359 win_skip("Number of assigned processes broken on Win 8\n");
2362 ULONG_PTR
*list
= pid_list
->ProcessIdList
;
2364 ok(ret_len
== FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[2]),
2365 "QueryInformationJobObject returned ret_len=%u\n", ret_len
);
2367 expect_eq_d(2, pid_list
->NumberOfAssignedProcesses
);
2368 expect_eq_d(2, pid_list
->NumberOfProcessIdsInList
);
2369 expect_eq_d(pi
[0].dwProcessId
, list
[0]);
2370 expect_eq_d(pi
[1].dwProcessId
, list
[1]);
2374 TerminateProcess(pi
[0].hProcess
, 0);
2375 CloseHandle(pi
[0].hProcess
);
2376 CloseHandle(pi
[0].hThread
);
2378 TerminateProcess(pi
[1].hProcess
, 0);
2379 CloseHandle(pi
[1].hProcess
);
2380 CloseHandle(pi
[1].hThread
);
2385 static void test_CompletionPort(void)
2387 JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info
;
2388 PROCESS_INFORMATION pi
;
2393 job
= pCreateJobObjectW(NULL
, NULL
);
2394 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2396 port
= pCreateIoCompletionPort(INVALID_HANDLE_VALUE
, NULL
, 0, 1);
2397 ok(port
!= NULL
, "CreateIoCompletionPort error %u\n", GetLastError());
2399 port_info
.CompletionKey
= job
;
2400 port_info
.CompletionPort
= port
;
2401 ret
= pSetInformationJobObject(job
, JobObjectAssociateCompletionPortInformation
, &port_info
, sizeof(port_info
));
2402 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2404 create_process("wait", &pi
);
2406 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2407 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2409 test_completion(port
, JOB_OBJECT_MSG_NEW_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2411 TerminateProcess(pi
.hProcess
, 0);
2412 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2413 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2415 test_completion(port
, JOB_OBJECT_MSG_EXIT_PROCESS
, (DWORD_PTR
)job
, pi
.dwProcessId
, 0);
2416 test_completion(port
, JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO
, (DWORD_PTR
)job
, 0, 100);
2418 CloseHandle(pi
.hProcess
);
2419 CloseHandle(pi
.hThread
);
2424 static void test_KillOnJobClose(void)
2426 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2427 PROCESS_INFORMATION pi
;
2432 job
= pCreateJobObjectW(NULL
, NULL
);
2433 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2435 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
;
2436 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2437 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
2439 win_skip("Kill on job close limit not available\n");
2442 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2444 create_process("wait", &pi
);
2446 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2447 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2451 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2453 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2454 if (dwret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0);
2456 CloseHandle(pi
.hProcess
);
2457 CloseHandle(pi
.hThread
);
2460 static void test_WaitForJobObject(void)
2463 PROCESS_INFORMATION pi
;
2467 /* test waiting for a job object when the process is killed */
2468 job
= pCreateJobObjectW(NULL
, NULL
);
2469 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2471 dwret
= WaitForSingleObject(job
, 100);
2472 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2474 create_process("wait", &pi
);
2476 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2477 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2479 dwret
= WaitForSingleObject(job
, 100);
2480 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2482 ret
= pTerminateJobObject(job
, 123);
2483 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2485 dwret
= WaitForSingleObject(job
, 500);
2486 ok(dwret
== WAIT_OBJECT_0
|| broken(dwret
== WAIT_TIMEOUT
),
2487 "WaitForSingleObject returned %u\n", dwret
);
2489 if (dwret
== WAIT_TIMEOUT
) /* Win 2000/XP */
2491 CloseHandle(pi
.hProcess
);
2492 CloseHandle(pi
.hThread
);
2494 win_skip("TerminateJobObject doesn't signal job, skipping tests\n");
2498 /* the object is not reset immediately */
2499 dwret
= WaitForSingleObject(job
, 100);
2500 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2502 CloseHandle(pi
.hProcess
);
2503 CloseHandle(pi
.hThread
);
2505 /* creating a new process doesn't reset the signalled state */
2506 create_process("wait", &pi
);
2508 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2509 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2511 dwret
= WaitForSingleObject(job
, 100);
2512 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2514 ret
= pTerminateJobObject(job
, 123);
2515 ok(ret
, "TerminateJobObject error %u\n", GetLastError());
2517 CloseHandle(pi
.hProcess
);
2518 CloseHandle(pi
.hThread
);
2522 /* repeat the test, but this time the process terminates properly */
2523 job
= pCreateJobObjectW(NULL
, NULL
);
2524 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2526 dwret
= WaitForSingleObject(job
, 100);
2527 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2529 create_process("exit", &pi
);
2531 ret
= pAssignProcessToJobObject(job
, pi
.hProcess
);
2532 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2534 dwret
= WaitForSingleObject(job
, 100);
2535 ok(dwret
== WAIT_TIMEOUT
, "WaitForSingleObject returned %u\n", dwret
);
2537 CloseHandle(pi
.hProcess
);
2538 CloseHandle(pi
.hThread
);
2542 static HANDLE
test_AddSelfToJob(void)
2547 job
= pCreateJobObjectW(NULL
, NULL
);
2548 ok(job
!= NULL
, "CreateJobObject error %u\n", GetLastError());
2550 ret
= pAssignProcessToJobObject(job
, GetCurrentProcess());
2551 ok(ret
, "AssignProcessToJobObject error %u\n", GetLastError());
2556 static void test_jobInheritance(HANDLE job
)
2558 char buffer
[MAX_PATH
];
2559 PROCESS_INFORMATION pi
;
2560 STARTUPINFOA si
= {0};
2564 if (!pIsProcessInJob
)
2566 win_skip("IsProcessInJob not available.\n");
2570 snprintf(buffer
, MAX_PATH
, "\"%s\" tests/process.c %s", selfname
, "exit");
2572 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2573 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2576 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2577 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2578 ok(out
, "IsProcessInJob returned out=%u\n", out
);
2580 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2581 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2583 CloseHandle(pi
.hProcess
);
2584 CloseHandle(pi
.hThread
);
2587 static void test_BreakawayOk(HANDLE job
)
2589 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info
;
2590 PROCESS_INFORMATION pi
;
2591 STARTUPINFOA si
= {0};
2592 char buffer
[MAX_PATH
];
2596 if (!pIsProcessInJob
)
2598 win_skip("IsProcessInJob not available.\n");
2602 snprintf(buffer
, MAX_PATH
, "\"%s\" tests/process.c %s", selfname
, "exit");
2604 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2605 ok(!ret
, "CreateProcessA expected failure\n");
2606 expect_eq_d(ERROR_ACCESS_DENIED
, GetLastError());
2610 TerminateProcess(pi
.hProcess
, 0);
2612 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2613 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2615 CloseHandle(pi
.hProcess
);
2616 CloseHandle(pi
.hThread
);
2619 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_BREAKAWAY_OK
;
2620 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2621 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2623 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_BREAKAWAY_FROM_JOB
, NULL
, NULL
, &si
, &pi
);
2624 ok(ret
, "CreateProcessA error %u\n", GetLastError());
2626 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2627 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2628 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2630 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2631 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2633 CloseHandle(pi
.hProcess
);
2634 CloseHandle(pi
.hThread
);
2636 limit_info
.BasicLimitInformation
.LimitFlags
= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
;
2637 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2638 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2640 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
2641 ok(ret
, "CreateProcess error %u\n", GetLastError());
2643 ret
= pIsProcessInJob(pi
.hProcess
, job
, &out
);
2644 ok(ret
, "IsProcessInJob error %u\n", GetLastError());
2645 ok(!out
, "IsProcessInJob returned out=%u\n", out
);
2647 dwret
= WaitForSingleObject(pi
.hProcess
, 1000);
2648 ok(dwret
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", dwret
);
2650 CloseHandle(pi
.hProcess
);
2651 CloseHandle(pi
.hThread
);
2653 /* unset breakaway ok */
2654 limit_info
.BasicLimitInformation
.LimitFlags
= 0;
2655 ret
= pSetInformationJobObject(job
, JobObjectExtendedLimitInformation
, &limit_info
, sizeof(limit_info
));
2656 ok(ret
, "SetInformationJobObject error %u\n", GetLastError());
2659 void test_StartupNoConsole(void)
2662 char buffer
[MAX_PATH
];
2663 STARTUPINFOA startup
;
2664 PROCESS_INFORMATION info
;
2669 win_skip( "NtCurrentTeb not supported\n" );
2673 memset(&startup
, 0, sizeof(startup
));
2674 startup
.cb
= sizeof(startup
);
2675 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
2676 startup
.wShowWindow
= SW_SHOWNORMAL
;
2677 get_file_name(resfile
);
2678 sprintf(buffer
, "\"%s\" tests/process.c dump \"%s\"", selfname
, resfile
);
2679 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
,
2680 &info
), "CreateProcess\n");
2681 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
2682 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
2683 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
2684 okChildInt("StartupInfoA", "hStdInput", (UINT
)INVALID_HANDLE_VALUE
);
2685 okChildInt("StartupInfoA", "hStdOutput", (UINT
)INVALID_HANDLE_VALUE
);
2686 okChildInt("StartupInfoA", "hStdError", (UINT
)INVALID_HANDLE_VALUE
);
2687 okChildInt("TEB", "hStdInput", 0);
2688 okChildInt("TEB", "hStdOutput", 0);
2689 okChildInt("TEB", "hStdError", 0);
2691 DeleteFileA(resfile
);
2699 ok(b
, "Basic init of CreateProcess test\n");
2704 if (!strcmp(myARGV
[2], "dump") && myARGC
>= 4)
2706 doChild(myARGV
[3], (myARGC
>= 5) ? myARGV
[4] : NULL
);
2709 else if (!strcmp(myARGV
[2], "wait"))
2712 ok(0, "Child process not killed\n");
2715 else if (!strcmp(myARGV
[2], "exit"))
2721 ok(0, "Unexpected command %s\n", myARGV
[2]);
2724 test_TerminateProcess();
2730 test_DebuggingFlag();
2734 test_GetProcessVersion();
2735 test_GetProcessImageFileNameA();
2736 test_QueryFullProcessImageNameA();
2737 test_QueryFullProcessImageNameW();
2739 test_IsWow64Process();
2741 test_RegistryQuota();
2742 test_DuplicateHandle();
2743 test_StartupNoConsole();
2744 /* things that can be tested:
2745 * lookup: check the way program to be executed is searched
2746 * handles: check the handle inheritance stuff (+sec options)
2747 * console: check if console creation parameters work
2750 if (!pCreateJobObjectW
)
2752 win_skip("No job object support\n");
2756 test_IsProcessInJob();
2757 test_TerminateJobObject();
2758 test_QueryInformationJobObject();
2759 test_CompletionPort();
2760 test_KillOnJobClose();
2761 test_WaitForJobObject();
2762 job
= test_AddSelfToJob();
2763 test_jobInheritance(job
);
2764 test_BreakawayOk(job
);