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
;
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
);
70 /* ############################### */
71 static char base
[MAX_PATH
];
72 static char selfname
[MAX_PATH
];
74 static char resfile
[MAX_PATH
];
79 /* As some environment variables get very long on Unix, we only test for
80 * the first 127 bytes.
81 * Note that increasing this value past 256 may exceed the buffer size
82 * limitations of the *Profile functions (at least on Wine).
84 #define MAX_LISTED_ENV_VAR 128
86 /* ---------------- portable memory allocation thingie */
88 static char memory
[1024*256];
89 static char* memory_index
= memory
;
91 static char* grab_memory(size_t len
)
93 char* ret
= memory_index
;
97 assert(memory_index
<= memory
+ sizeof(memory
));
101 static void release_memory(void)
103 memory_index
= memory
;
106 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
108 static const char* encodeA(const char* str
)
114 len
= strlen(str
) + 1;
115 ptr
= grab_memory(len
* 2 + 1);
116 for (i
= 0; i
< len
; i
++)
117 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
122 static const char* encodeW(const WCHAR
* str
)
128 len
= lstrlenW(str
) + 1;
129 ptr
= grab_memory(len
* 4 + 1);
131 for (i
= 0; i
< len
; i
++)
132 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
137 static unsigned decode_char(char c
)
139 if (c
>= '0' && c
<= '9') return c
- '0';
140 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
141 assert(c
>= 'A' && c
<= 'F');
145 static char* decodeA(const char* str
)
150 len
= strlen(str
) / 2;
151 if (!len
--) return NULL
;
152 ptr
= grab_memory(len
+ 1);
153 for (i
= 0; i
< len
; i
++)
154 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
159 /* This will be needed to decode Unicode strings saved by the child process
160 * when we test Unicode functions.
162 static WCHAR
* decodeW(const char* str
)
168 len
= strlen(str
) / 4;
169 if (!len
--) return NULL
;
170 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
171 for (i
= 0; i
< len
; i
++)
172 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
173 (decode_char(str
[4 * i
+ 1]) << 8) |
174 (decode_char(str
[4 * i
+ 2]) << 4) |
175 (decode_char(str
[4 * i
+ 3]) << 0);
180 /******************************************************************
183 * generates basic information like:
184 * base: absolute path to curr dir
185 * selfname: the way to reinvoke ourselves
186 * exename: executable without the path
187 * function-pointers, which are not implemented in all windows versions
189 static BOOL
init(void)
193 myARGC
= winetest_get_mainargs( &myARGV
);
194 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return FALSE
;
195 strcpy(selfname
, myARGV
[0]);
197 /* Strip the path of selfname */
198 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
199 else exename
= selfname
;
201 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
203 hkernel32
= GetModuleHandleA("kernel32");
204 pGetNativeSystemInfo
= (void *) GetProcAddress(hkernel32
, "GetNativeSystemInfo");
205 pGetSystemRegistryQuota
= (void *) GetProcAddress(hkernel32
, "GetSystemRegistryQuota");
206 pIsWow64Process
= (void *) GetProcAddress(hkernel32
, "IsWow64Process");
207 pVirtualAllocEx
= (void *) GetProcAddress(hkernel32
, "VirtualAllocEx");
208 pVirtualFreeEx
= (void *) GetProcAddress(hkernel32
, "VirtualFreeEx");
209 pQueryFullProcessImageNameA
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameA");
210 pQueryFullProcessImageNameW
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameW");
211 pK32GetProcessImageFileNameA
= (void *) GetProcAddress(hkernel32
, "K32GetProcessImageFileNameA");
215 /******************************************************************
218 * generates an absolute file_name for temporary file
221 static void get_file_name(char* buf
)
226 GetTempPathA(sizeof(path
), path
);
227 GetTempFileNameA(path
, "wt", 0, buf
);
230 /******************************************************************
231 * static void childPrintf
234 static void childPrintf(HANDLE h
, const char* fmt
, ...)
237 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
240 va_start(valist
, fmt
);
241 vsprintf(buffer
, fmt
, valist
);
243 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
247 /******************************************************************
250 * output most of the information in the child process
252 static void doChild(const char* file
, const char* option
)
257 char *ptrA
, *ptrA_save
;
258 WCHAR
*ptrW
, *ptrW_save
;
260 WCHAR bufW
[MAX_PATH
];
261 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
264 if (hFile
== INVALID_HANDLE_VALUE
) return;
266 /* output of startup info (Ansi) */
267 GetStartupInfoA(&siA
);
269 "[StartupInfoA]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
270 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
271 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
272 "dwFlags=%lu\nwShowWindow=%u\n"
273 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
274 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
275 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
276 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
277 siA
.dwFlags
, siA
.wShowWindow
,
278 (DWORD_PTR
)siA
.hStdInput
, (DWORD_PTR
)siA
.hStdOutput
, (DWORD_PTR
)siA
.hStdError
);
280 /* since GetStartupInfoW is only implemented in win2k,
281 * zero out before calling so we can notice the difference
283 memset(&siW
, 0, sizeof(siW
));
284 GetStartupInfoW(&siW
);
286 "[StartupInfoW]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
287 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
288 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
289 "dwFlags=%lu\nwShowWindow=%u\n"
290 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
291 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
292 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
293 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
294 siW
.dwFlags
, siW
.wShowWindow
,
295 (DWORD_PTR
)siW
.hStdInput
, (DWORD_PTR
)siW
.hStdOutput
, (DWORD_PTR
)siW
.hStdError
);
298 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
299 for (i
= 0; i
< myARGC
; i
++)
301 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
303 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
304 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
306 /* output of environment (Ansi) */
307 ptrA_save
= ptrA
= GetEnvironmentStringsA();
310 char env_var
[MAX_LISTED_ENV_VAR
];
312 childPrintf(hFile
, "[EnvironmentA]\n");
316 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
317 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
319 ptrA
+= strlen(ptrA
) + 1;
321 childPrintf(hFile
, "len=%d\n\n", i
);
322 FreeEnvironmentStringsA(ptrA_save
);
325 /* output of environment (Unicode) */
326 ptrW_save
= ptrW
= GetEnvironmentStringsW();
329 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
331 childPrintf(hFile
, "[EnvironmentW]\n");
335 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
336 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
337 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
339 ptrW
+= lstrlenW(ptrW
) + 1;
341 childPrintf(hFile
, "len=%d\n\n", i
);
342 FreeEnvironmentStringsW(ptrW_save
);
345 childPrintf(hFile
, "[Misc]\n");
346 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
347 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
348 if (GetCurrentDirectoryW(sizeof(bufW
) / sizeof(bufW
[0]), bufW
))
349 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
350 childPrintf(hFile
, "\n");
352 if (option
&& strcmp(option
, "console") == 0)
354 CONSOLE_SCREEN_BUFFER_INFO sbi
;
355 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
356 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
357 DWORD modeIn
, modeOut
;
359 childPrintf(hFile
, "[Console]\n");
360 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
362 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
363 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
364 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
365 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
366 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
367 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
369 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
370 GetConsoleCP(), GetConsoleOutputCP());
371 if (GetConsoleMode(hConIn
, &modeIn
))
372 childPrintf(hFile
, "InputMode=%ld\n", modeIn
);
373 if (GetConsoleMode(hConOut
, &modeOut
))
374 childPrintf(hFile
, "OutputMode=%ld\n", modeOut
);
376 /* now that we have written all relevant information, let's change it */
377 SetLastError(0xdeadbeef);
378 ret
= SetConsoleCP(1252);
379 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
381 win_skip("Setting the codepage is not implemented\n");
385 ok(ret
, "Setting CP\n");
386 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
389 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
390 ok( ret
, "Setting mode (%d)\n", GetLastError());
391 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
392 ok( ret
, "Setting mode (%d)\n", GetLastError());
393 sbi
.dwCursorPosition
.X
^= 1;
394 sbi
.dwCursorPosition
.Y
^= 1;
395 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
396 ok( ret
, "Setting cursor position (%d)\n", GetLastError());
398 if (option
&& strcmp(option
, "stdhandle") == 0)
400 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
401 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
403 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
408 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
409 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
410 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
414 if (option
&& strcmp(option
, "exit_code") == 0)
416 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
424 static char* getChildString(const char* sect
, const char* key
)
426 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
429 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
430 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
431 assert(!(strlen(buf
) & 1));
436 static WCHAR
* getChildStringW(const char* sect
, const char* key
)
438 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
441 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
442 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
443 assert(!(strlen(buf
) & 1));
448 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
449 * others... (windows uses stricmp while Un*x uses strcasecmp...)
451 static int wtstrcasecmp(const char* p1
, const char* p2
)
456 while (c1
== c2
&& c1
)
458 c1
= *p1
++; c2
= *p2
++;
461 c1
= toupper(c1
); c2
= toupper(c2
);
467 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
469 if (!s1
&& !s2
) return 0;
472 return (sensitive
) ? strcmp(s1
, s2
) : wtstrcasecmp(s1
, s2
);
475 static void ok_child_string( int line
, const char *sect
, const char *key
,
476 const char *expect
, int sensitive
)
478 char* result
= getChildString( sect
, key
);
479 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
480 sect
, key
, expect
? expect
: "(null)", result
);
483 static void ok_child_stringWA( int line
, const char *sect
, const char *key
,
484 const char *expect
, int sensitive
)
489 WCHAR
* result
= getChildStringW( sect
, key
);
491 len
= MultiByteToWideChar( CP_ACP
, 0, expect
, -1, NULL
, 0);
492 expectW
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
493 MultiByteToWideChar( CP_ACP
, 0, expect
, -1, expectW
, len
);
495 len
= WideCharToMultiByte( CP_ACP
, 0, result
, -1, NULL
, 0, NULL
, NULL
);
496 resultA
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(CHAR
));
497 WideCharToMultiByte( CP_ACP
, 0, result
, -1, resultA
, len
, NULL
, NULL
);
500 ok_(__FILE__
, line
)( lstrcmpW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
501 sect
, key
, expect
? expect
: "(null)", resultA
);
503 ok_(__FILE__
, line
)( lstrcmpiW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
504 sect
, key
, expect
? expect
: "(null)", resultA
);
505 HeapFree(GetProcessHeap(),0,expectW
);
506 HeapFree(GetProcessHeap(),0,resultA
);
509 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
510 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
511 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
513 /* using !expect ensures that the test will fail if the sect/key isn't present
516 #define okChildInt(sect, key, expect) \
518 UINT result = GetPrivateProfileIntA((sect), (key), !(expect), resfile); \
519 ok(result == expect, "%s:%s expected %u, but got %u\n", (sect), (key), (UINT)(expect), result); \
522 static void test_Startup(void)
524 char buffer
[MAX_PATH
];
525 PROCESS_INFORMATION info
;
526 STARTUPINFOA startup
,si
;
528 static CHAR title
[] = "I'm the title string",
529 desktop
[] = "winsta0\\default",
532 /* let's start simplistic */
533 memset(&startup
, 0, sizeof(startup
));
534 startup
.cb
= sizeof(startup
);
535 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
536 startup
.wShowWindow
= SW_SHOWNORMAL
;
538 get_file_name(resfile
);
539 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
540 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
541 /* wait for child to terminate */
542 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
543 /* child process has changed result file, so let profile functions know about it */
544 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
546 GetStartupInfoA(&si
);
547 okChildInt("StartupInfoA", "cb", startup
.cb
);
548 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
549 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
550 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
551 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
552 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
553 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
554 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
555 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
556 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
557 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
559 assert(DeleteFileA(resfile
) != 0);
561 /* not so simplistic now */
562 memset(&startup
, 0, sizeof(startup
));
563 startup
.cb
= sizeof(startup
);
564 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
565 startup
.wShowWindow
= SW_SHOWNORMAL
;
566 startup
.lpTitle
= title
;
567 startup
.lpDesktop
= desktop
;
568 startup
.dwXCountChars
= 0x12121212;
569 startup
.dwYCountChars
= 0x23232323;
570 startup
.dwX
= 0x34343434;
571 startup
.dwY
= 0x45454545;
572 startup
.dwXSize
= 0x56565656;
573 startup
.dwYSize
= 0x67676767;
574 startup
.dwFillAttribute
= 0xA55A;
576 get_file_name(resfile
);
577 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
578 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
579 /* wait for child to terminate */
580 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
581 /* child process has changed result file, so let profile functions know about it */
582 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
584 okChildInt("StartupInfoA", "cb", startup
.cb
);
585 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
586 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
587 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
588 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
589 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
590 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
591 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
592 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
593 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
594 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
595 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
597 assert(DeleteFileA(resfile
) != 0);
599 /* not so simplistic now */
600 memset(&startup
, 0, sizeof(startup
));
601 startup
.cb
= sizeof(startup
);
602 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
603 startup
.wShowWindow
= SW_SHOWNORMAL
;
604 startup
.lpTitle
= title
;
605 startup
.lpDesktop
= NULL
;
606 startup
.dwXCountChars
= 0x12121212;
607 startup
.dwYCountChars
= 0x23232323;
608 startup
.dwX
= 0x34343434;
609 startup
.dwY
= 0x45454545;
610 startup
.dwXSize
= 0x56565656;
611 startup
.dwYSize
= 0x67676767;
612 startup
.dwFillAttribute
= 0xA55A;
614 get_file_name(resfile
);
615 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
616 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
617 /* wait for child to terminate */
618 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
619 /* child process has changed result file, so let profile functions know about it */
620 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
622 okChildInt("StartupInfoA", "cb", startup
.cb
);
623 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
624 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
625 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
626 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
627 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
628 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
629 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
630 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
631 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
632 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
633 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
635 assert(DeleteFileA(resfile
) != 0);
637 /* not so simplistic now */
638 memset(&startup
, 0, sizeof(startup
));
639 startup
.cb
= sizeof(startup
);
640 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
641 startup
.wShowWindow
= SW_SHOWNORMAL
;
642 startup
.lpTitle
= title
;
643 startup
.lpDesktop
= empty
;
644 startup
.dwXCountChars
= 0x12121212;
645 startup
.dwYCountChars
= 0x23232323;
646 startup
.dwX
= 0x34343434;
647 startup
.dwY
= 0x45454545;
648 startup
.dwXSize
= 0x56565656;
649 startup
.dwYSize
= 0x67676767;
650 startup
.dwFillAttribute
= 0xA55A;
652 get_file_name(resfile
);
653 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
654 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
655 /* wait for child to terminate */
656 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
657 /* child process has changed result file, so let profile functions know about it */
658 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
660 okChildInt("StartupInfoA", "cb", startup
.cb
);
661 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
662 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
663 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
664 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
665 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
666 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
667 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
668 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
669 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
670 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
671 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
673 assert(DeleteFileA(resfile
) != 0);
675 /* not so simplistic now */
676 memset(&startup
, 0, sizeof(startup
));
677 startup
.cb
= sizeof(startup
);
678 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
679 startup
.wShowWindow
= SW_SHOWNORMAL
;
680 startup
.lpTitle
= NULL
;
681 startup
.lpDesktop
= desktop
;
682 startup
.dwXCountChars
= 0x12121212;
683 startup
.dwYCountChars
= 0x23232323;
684 startup
.dwX
= 0x34343434;
685 startup
.dwY
= 0x45454545;
686 startup
.dwXSize
= 0x56565656;
687 startup
.dwYSize
= 0x67676767;
688 startup
.dwFillAttribute
= 0xA55A;
690 get_file_name(resfile
);
691 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
692 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
693 /* wait for child to terminate */
694 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
695 /* child process has changed result file, so let profile functions know about it */
696 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
698 okChildInt("StartupInfoA", "cb", startup
.cb
);
699 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
700 result
= getChildString( "StartupInfoA", "lpTitle" );
701 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
702 "expected '%s' or null, got '%s'\n", selfname
, result
);
703 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
704 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
705 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
706 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
707 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
708 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
709 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
710 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
711 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
713 assert(DeleteFileA(resfile
) != 0);
715 /* not so simplistic now */
716 memset(&startup
, 0, sizeof(startup
));
717 startup
.cb
= sizeof(startup
);
718 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
719 startup
.wShowWindow
= SW_SHOWNORMAL
;
720 startup
.lpTitle
= empty
;
721 startup
.lpDesktop
= desktop
;
722 startup
.dwXCountChars
= 0x12121212;
723 startup
.dwYCountChars
= 0x23232323;
724 startup
.dwX
= 0x34343434;
725 startup
.dwY
= 0x45454545;
726 startup
.dwXSize
= 0x56565656;
727 startup
.dwYSize
= 0x67676767;
728 startup
.dwFillAttribute
= 0xA55A;
730 get_file_name(resfile
);
731 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
732 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
733 /* wait for child to terminate */
734 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
735 /* child process has changed result file, so let profile functions know about it */
736 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
738 okChildInt("StartupInfoA", "cb", startup
.cb
);
739 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
740 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
741 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
742 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
743 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
744 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
745 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
746 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
747 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
748 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
749 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
751 assert(DeleteFileA(resfile
) != 0);
753 /* not so simplistic now */
754 memset(&startup
, 0, sizeof(startup
));
755 startup
.cb
= sizeof(startup
);
756 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
757 startup
.wShowWindow
= SW_SHOWNORMAL
;
758 startup
.lpTitle
= empty
;
759 startup
.lpDesktop
= empty
;
760 startup
.dwXCountChars
= 0x12121212;
761 startup
.dwYCountChars
= 0x23232323;
762 startup
.dwX
= 0x34343434;
763 startup
.dwY
= 0x45454545;
764 startup
.dwXSize
= 0x56565656;
765 startup
.dwYSize
= 0x67676767;
766 startup
.dwFillAttribute
= 0xA55A;
768 get_file_name(resfile
);
769 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
770 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
771 /* wait for child to terminate */
772 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
773 /* child process has changed result file, so let profile functions know about it */
774 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
776 okChildInt("StartupInfoA", "cb", startup
.cb
);
777 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
778 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
779 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
780 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
781 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
782 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
783 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
784 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
785 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
786 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
787 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
789 assert(DeleteFileA(resfile
) != 0);
791 /* TODO: test for A/W and W/A and W/W */
794 static void test_CommandLine(void)
796 char buffer
[MAX_PATH
], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
797 char buffer2
[MAX_PATH
];
798 PROCESS_INFORMATION info
;
799 STARTUPINFOA startup
;
802 memset(&startup
, 0, sizeof(startup
));
803 startup
.cb
= sizeof(startup
);
804 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
805 startup
.wShowWindow
= SW_SHOWNORMAL
;
808 get_file_name(resfile
);
809 sprintf(buffer
, "\"%s\" tests/process.c \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
810 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
811 /* wait for child to terminate */
812 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
813 /* child process has changed result file, so let profile functions know about it */
814 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
816 okChildInt("Arguments", "argcA", 4);
817 okChildString("Arguments", "argvA3", "C:\\Program Files\\my nice app.exe");
818 okChildString("Arguments", "argvA4", NULL
);
819 okChildString("Arguments", "CommandLineA", buffer
);
821 assert(DeleteFileA(resfile
) != 0);
823 memset(&startup
, 0, sizeof(startup
));
824 startup
.cb
= sizeof(startup
);
825 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
826 startup
.wShowWindow
= SW_SHOWNORMAL
;
829 get_file_name(resfile
);
830 sprintf(buffer
, "\"%s\" tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", selfname
, resfile
);
831 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
832 /* wait for child to terminate */
833 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
834 /* child process has changed result file, so let profile functions know about it */
835 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
837 okChildInt("Arguments", "argcA", 6);
838 okChildString("Arguments", "argvA3", "a\"b\\");
839 okChildString("Arguments", "argvA4", "c\"");
840 okChildString("Arguments", "argvA5", "d");
841 okChildString("Arguments", "argvA6", NULL
);
842 okChildString("Arguments", "CommandLineA", buffer
);
844 assert(DeleteFileA(resfile
) != 0);
846 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
847 get_file_name(resfile
);
848 /* Use exename to avoid buffer containing things like 'C:' */
849 sprintf(buffer
, "./%s tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
850 SetLastError(0xdeadbeef);
851 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
852 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
853 /* wait for child to terminate */
854 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
855 /* child process has changed result file, so let profile functions know about it */
856 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
857 sprintf(buffer
, "./%s", exename
);
858 okChildString("Arguments", "argvA0", buffer
);
860 assert(DeleteFileA(resfile
) != 0);
862 get_file_name(resfile
);
863 /* Use exename to avoid buffer containing things like 'C:' */
864 sprintf(buffer
, ".\\%s tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
865 SetLastError(0xdeadbeef);
866 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
867 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
868 /* wait for child to terminate */
869 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
870 /* child process has changed result file, so let profile functions know about it */
871 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
872 sprintf(buffer
, ".\\%s", exename
);
873 okChildString("Arguments", "argvA0", buffer
);
875 assert(DeleteFileA(resfile
) != 0);
877 get_file_name(resfile
);
878 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
879 assert ( lpFilePart
!= 0);
880 *(lpFilePart
-1 ) = 0;
881 p
= strrchr(fullpath
, '\\');
882 /* Use exename to avoid buffer containing things like 'C:' */
883 if (p
) sprintf(buffer
, "..%s/%s tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", p
, exename
, resfile
);
884 else sprintf(buffer
, "./%s tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
885 SetLastError(0xdeadbeef);
886 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
887 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
888 /* wait for child to terminate */
889 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
890 /* child process has changed result file, so let profile functions know about it */
891 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
892 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
893 else sprintf(buffer
, "./%s", exename
);
894 okChildString("Arguments", "argvA0", buffer
);
896 assert(DeleteFileA(resfile
) != 0);
899 get_file_name(resfile
);
900 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
901 assert ( lpFilePart
!= 0);
902 *(lpFilePart
-1 ) = 0;
903 p
= strrchr(fullpath
, '\\');
904 /* Use exename to avoid buffer containing things like 'C:' */
905 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
906 else sprintf(buffer
, "./%s", exename
);
907 sprintf(buffer2
, "dummy tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile
);
908 SetLastError(0xdeadbeef);
909 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
910 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
911 /* wait for child to terminate */
912 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
913 /* child process has changed result file, so let profile functions know about it */
914 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
915 sprintf(buffer
, "tests/process.c %s", resfile
);
916 okChildString("Arguments", "argvA0", "dummy");
917 okChildString("Arguments", "CommandLineA", buffer2
);
918 okChildStringWA("Arguments", "CommandLineW", buffer2
);
920 assert(DeleteFileA(resfile
) != 0);
922 if (0) /* Test crashes on NT-based Windows. */
924 /* Test NULL application name and command line parameters. */
925 SetLastError(0xdeadbeef);
926 ret
= CreateProcessA(NULL
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
927 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
928 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
929 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
934 /* Test empty application name parameter. */
935 SetLastError(0xdeadbeef);
936 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
937 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
938 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
939 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
940 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
941 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
945 /* Test empty application name and command line parameters. */
946 SetLastError(0xdeadbeef);
947 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
948 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
949 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
950 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
951 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
952 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
954 /* Test empty command line parameter. */
955 SetLastError(0xdeadbeef);
956 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
957 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
958 ok(GetLastError() == ERROR_FILE_NOT_FOUND
||
959 GetLastError() == ERROR_PATH_NOT_FOUND
/* NT4 */ ||
960 GetLastError() == ERROR_BAD_PATHNAME
/* Win98 */ ||
961 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7 */,
962 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
964 strcpy(buffer
, "doesnotexist.exe");
965 strcpy(buffer2
, "does not exist.exe");
967 /* Test nonexistent application name. */
968 SetLastError(0xdeadbeef);
969 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
970 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
971 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
973 SetLastError(0xdeadbeef);
974 ret
= CreateProcessA(buffer2
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
975 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
976 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
978 /* Test nonexistent command line parameter. */
979 SetLastError(0xdeadbeef);
980 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
981 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
982 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
984 SetLastError(0xdeadbeef);
985 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
986 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
987 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
990 static void test_Directory(void)
992 char buffer
[MAX_PATH
];
993 PROCESS_INFORMATION info
;
994 STARTUPINFOA startup
;
995 char windir
[MAX_PATH
];
996 static CHAR cmdline
[] = "winver.exe";
998 memset(&startup
, 0, sizeof(startup
));
999 startup
.cb
= sizeof(startup
);
1000 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1001 startup
.wShowWindow
= SW_SHOWNORMAL
;
1004 get_file_name(resfile
);
1005 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1006 GetWindowsDirectoryA( windir
, sizeof(windir
) );
1007 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
1008 /* wait for child to terminate */
1009 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1010 /* child process has changed result file, so let profile functions know about it */
1011 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1013 okChildIString("Misc", "CurrDirA", windir
);
1015 assert(DeleteFileA(resfile
) != 0);
1017 /* search PATH for the exe if directory is NULL */
1018 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1019 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
1021 /* if any directory is provided, don't search PATH, error on bad directory */
1022 SetLastError(0xdeadbeef);
1023 memset(&info
, 0, sizeof(info
));
1024 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
1025 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
1026 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1027 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
1030 static BOOL
is_str_env_drive_dir(const char* str
)
1032 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1033 str
[3] == '=' && str
[4] == str
[1];
1036 /* compared expected child's environment (in gesA) from actual
1037 * environment our child got
1039 static void cmpEnvironment(const char* gesA
)
1047 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1049 /* now look each parent env in child */
1050 if ((ptrA
= gesA
) != NULL
)
1054 for (i
= 0; i
< clen
; i
++)
1056 sprintf(key
, "env%d", i
);
1057 res
= getChildString("EnvironmentA", key
);
1058 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1062 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1064 ptrA
+= strlen(ptrA
) + 1;
1068 /* and each child env in parent */
1069 for (i
= 0; i
< clen
; i
++)
1071 sprintf(key
, "env%d", i
);
1072 res
= getChildString("EnvironmentA", key
);
1073 if ((ptrA
= gesA
) != NULL
)
1077 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1079 ptrA
+= strlen(ptrA
) + 1;
1081 if (!*ptrA
) ptrA
= NULL
;
1084 if (!is_str_env_drive_dir(res
))
1086 found
= ptrA
!= NULL
;
1087 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1089 /* else => should also test we get the right per drive default directory here... */
1093 static void test_Environment(void)
1095 char buffer
[MAX_PATH
];
1096 PROCESS_INFORMATION info
;
1097 STARTUPINFOA startup
;
1105 memset(&startup
, 0, sizeof(startup
));
1106 startup
.cb
= sizeof(startup
);
1107 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1108 startup
.wShowWindow
= SW_SHOWNORMAL
;
1111 get_file_name(resfile
);
1112 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1113 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1114 /* wait for child to terminate */
1115 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1116 /* child process has changed result file, so let profile functions know about it */
1117 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1119 env
= GetEnvironmentStringsA();
1120 cmpEnvironment(env
);
1122 assert(DeleteFileA(resfile
) != 0);
1124 memset(&startup
, 0, sizeof(startup
));
1125 startup
.cb
= sizeof(startup
);
1126 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1127 startup
.wShowWindow
= SW_SHOWNORMAL
;
1130 get_file_name(resfile
);
1131 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1137 slen
= strlen(ptr
)+1;
1138 child_env_len
+= slen
;
1141 /* Add space for additional environment variables */
1142 child_env_len
+= 256;
1143 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1146 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1147 ptr
+= strlen(ptr
) + 1;
1148 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1149 ptr
+= strlen(ptr
) + 1;
1150 strcpy(ptr
, "FOO=BAR");
1151 ptr
+= strlen(ptr
) + 1;
1152 strcpy(ptr
, "BAR=FOOBAR");
1153 ptr
+= strlen(ptr
) + 1;
1154 /* copy all existing variables except:
1156 * - PATH (already set above)
1157 * - the directory definitions (=[A-Z]:=)
1159 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1161 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1162 strncmp(ptr2
, "WINELOADER=", 11) != 0 &&
1163 !is_str_env_drive_dir(ptr2
))
1166 ptr
+= strlen(ptr
) + 1;
1170 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1171 /* wait for child to terminate */
1172 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1173 /* child process has changed result file, so let profile functions know about it */
1174 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1176 cmpEnvironment(child_env
);
1178 HeapFree(GetProcessHeap(), 0, child_env
);
1179 FreeEnvironmentStringsA(env
);
1181 assert(DeleteFileA(resfile
) != 0);
1184 static void test_SuspendFlag(void)
1186 char buffer
[MAX_PATH
];
1187 PROCESS_INFORMATION info
;
1188 STARTUPINFOA startup
, us
;
1192 /* let's start simplistic */
1193 memset(&startup
, 0, sizeof(startup
));
1194 startup
.cb
= sizeof(startup
);
1195 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1196 startup
.wShowWindow
= SW_SHOWNORMAL
;
1198 get_file_name(resfile
);
1199 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1200 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1202 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1204 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1205 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1207 /* wait for child to terminate */
1208 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1209 /* child process has changed result file, so let profile functions know about it */
1210 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1212 GetStartupInfoA(&us
);
1214 okChildInt("StartupInfoA", "cb", startup
.cb
);
1215 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1216 result
= getChildString( "StartupInfoA", "lpTitle" );
1217 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1218 "expected '%s' or null, got '%s'\n", selfname
, result
);
1219 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1220 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1221 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1222 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1223 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1224 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1225 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1226 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1227 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1229 assert(DeleteFileA(resfile
) != 0);
1232 static void test_DebuggingFlag(void)
1234 char buffer
[MAX_PATH
];
1235 void *processbase
= NULL
;
1236 PROCESS_INFORMATION info
;
1237 STARTUPINFOA startup
, us
;
1242 /* let's start simplistic */
1243 memset(&startup
, 0, sizeof(startup
));
1244 startup
.cb
= sizeof(startup
);
1245 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1246 startup
.wShowWindow
= SW_SHOWNORMAL
;
1248 get_file_name(resfile
);
1249 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1250 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1252 /* get all startup events up to the entry point break exception */
1255 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1256 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1259 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1260 "first event: %d\n", de
.dwDebugEventCode
);
1261 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1263 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1264 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1265 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1266 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1268 ok(dbg
, "I have seen a debug event\n");
1269 /* wait for child to terminate */
1270 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1271 /* child process has changed result file, so let profile functions know about it */
1272 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1274 GetStartupInfoA(&us
);
1276 okChildInt("StartupInfoA", "cb", startup
.cb
);
1277 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1278 result
= getChildString( "StartupInfoA", "lpTitle" );
1279 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1280 "expected '%s' or null, got '%s'\n", selfname
, result
);
1281 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1282 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1283 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1284 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1285 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1286 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1287 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1288 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1289 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1291 assert(DeleteFileA(resfile
) != 0);
1294 static BOOL
is_console(HANDLE h
)
1296 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1299 static void test_Console(void)
1301 char buffer
[MAX_PATH
];
1302 PROCESS_INFORMATION info
;
1303 STARTUPINFOA startup
, us
;
1304 SECURITY_ATTRIBUTES sa
;
1305 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1306 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1307 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1309 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1310 const char* msg
= "This is a std-handle inheritance test.";
1312 BOOL run_tests
= TRUE
;
1315 memset(&startup
, 0, sizeof(startup
));
1316 startup
.cb
= sizeof(startup
);
1317 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1318 startup
.wShowWindow
= SW_SHOWNORMAL
;
1320 sa
.nLength
= sizeof(sa
);
1321 sa
.lpSecurityDescriptor
= NULL
;
1322 sa
.bInheritHandle
= TRUE
;
1324 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1325 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1327 /* first, we need to be sure we're attached to a console */
1328 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1330 /* we're not attached to a console, let's do it */
1332 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1333 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1335 /* now verify everything's ok */
1336 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1337 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1338 startup
.hStdError
= startup
.hStdOutput
;
1340 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1341 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
) &&
1342 GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console modes\n");
1343 cpIn
= GetConsoleCP();
1344 cpOut
= GetConsoleOutputCP();
1346 get_file_name(resfile
);
1347 sprintf(buffer
, "\"%s\" tests/process.c \"%s\" console", selfname
, resfile
);
1348 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1350 /* wait for child to terminate */
1351 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1352 /* child process has changed result file, so let profile functions know about it */
1353 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1355 /* now get the modification the child has made, and resets parents expected values */
1356 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1357 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
) &&
1358 GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console modes\n");
1360 SetConsoleMode(startup
.hStdInput
, modeIn
);
1361 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1363 cpInC
= GetConsoleCP();
1364 cpOutC
= GetConsoleOutputCP();
1366 /* Try to set invalid CP */
1367 SetLastError(0xdeadbeef);
1368 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1369 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1370 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1371 "GetLastError: expecting %u got %u\n",
1372 ERROR_INVALID_PARAMETER
, GetLastError());
1373 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1377 SetLastError(0xdeadbeef);
1378 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1379 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1380 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1381 "GetLastError: expecting %u got %u\n",
1382 ERROR_INVALID_PARAMETER
, GetLastError());
1385 SetConsoleOutputCP(cpOut
);
1387 GetStartupInfoA(&us
);
1389 okChildInt("StartupInfoA", "cb", startup
.cb
);
1390 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1391 result
= getChildString( "StartupInfoA", "lpTitle" );
1392 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1393 "expected '%s' or null, got '%s'\n", selfname
, result
);
1394 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1395 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1396 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1397 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1398 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1399 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1400 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1401 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1402 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1404 /* check child correctly inherited the console */
1405 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1406 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1407 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1408 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1409 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1410 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1411 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1412 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1413 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1414 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1415 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1416 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1417 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1418 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1419 okChildInt("Console", "InputCP", cpIn
);
1420 okChildInt("Console", "OutputCP", cpOut
);
1421 okChildInt("Console", "InputMode", modeIn
);
1422 okChildInt("Console", "OutputMode", modeOut
);
1426 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1427 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1430 win_skip("Setting the codepage is not implemented\n");
1432 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1433 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1434 trace("cursor position(X): %d/%d\n",sbi
.dwCursorPosition
.X
, sbiC
.dwCursorPosition
.X
);
1435 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1438 assert(DeleteFileA(resfile
) != 0);
1440 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1441 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1442 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1443 "Duplicating as inheritable child-output pipe\n");
1444 CloseHandle(hChildOut
);
1446 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1447 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1448 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1449 "Duplicating as inheritable child-input pipe\n");
1450 CloseHandle(hChildIn
);
1452 memset(&startup
, 0, sizeof(startup
));
1453 startup
.cb
= sizeof(startup
);
1454 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1455 startup
.wShowWindow
= SW_SHOWNORMAL
;
1456 startup
.hStdInput
= hChildInInh
;
1457 startup
.hStdOutput
= hChildOutInh
;
1458 startup
.hStdError
= hChildOutInh
;
1460 get_file_name(resfile
);
1461 sprintf(buffer
, "\"%s\" tests/process.c \"%s\" stdhandle", selfname
, resfile
);
1462 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1463 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1464 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1466 msg_len
= strlen(msg
) + 1;
1467 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1468 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1469 memset(buffer
, 0, sizeof(buffer
));
1470 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1471 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1473 /* wait for child to terminate */
1474 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1475 /* child process has changed result file, so let profile functions know about it */
1476 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1478 okChildString("StdHandle", "msg", msg
);
1481 assert(DeleteFileA(resfile
) != 0);
1484 static void test_ExitCode(void)
1486 char buffer
[MAX_PATH
];
1487 PROCESS_INFORMATION info
;
1488 STARTUPINFOA startup
;
1491 /* let's start simplistic */
1492 memset(&startup
, 0, sizeof(startup
));
1493 startup
.cb
= sizeof(startup
);
1494 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1495 startup
.wShowWindow
= SW_SHOWNORMAL
;
1497 get_file_name(resfile
);
1498 sprintf(buffer
, "\"%s\" tests/process.c \"%s\" exit_code", selfname
, resfile
);
1499 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
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 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1507 okChildInt("ExitCode", "value", code
);
1510 assert(DeleteFileA(resfile
) != 0);
1513 static void test_OpenProcess(void)
1517 MEMORY_BASIC_INFORMATION info
;
1518 SIZE_T dummy
, read_bytes
;
1521 /* not exported in all windows versions */
1522 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1523 win_skip("VirtualAllocEx not found\n");
1527 /* without PROCESS_VM_OPERATION */
1528 hproc
= OpenProcess(PROCESS_ALL_ACCESS_NT4
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1529 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1531 SetLastError(0xdeadbeef);
1532 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1533 ok(!addr1
, "VirtualAllocEx should fail\n");
1534 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1537 win_skip("VirtualAllocEx not implemented\n");
1540 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1542 read_bytes
= 0xdeadbeef;
1543 SetLastError(0xdeadbeef);
1544 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1545 ok(ret
, "ReadProcessMemory error %d\n", GetLastError());
1546 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1550 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1551 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1553 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1554 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1556 /* without PROCESS_QUERY_INFORMATION */
1557 SetLastError(0xdeadbeef);
1558 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1559 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1560 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1562 /* without PROCESS_VM_READ */
1563 read_bytes
= 0xdeadbeef;
1564 SetLastError(0xdeadbeef);
1565 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1566 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1567 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1568 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1572 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1574 memset(&info
, 0xcc, sizeof(info
));
1575 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1576 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1578 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1579 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1580 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1581 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1582 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1583 /* NT reports Protect == 0 for a not committed memory block */
1584 ok(info
.Protect
== 0 /* NT */ ||
1585 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1586 "%x != PAGE_NOACCESS\n", info
.Protect
);
1587 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1589 SetLastError(0xdeadbeef);
1590 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1591 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1592 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1596 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1599 static void test_GetProcessVersion(void)
1601 static char cmdline
[] = "winver.exe";
1602 PROCESS_INFORMATION pi
;
1606 SetLastError(0xdeadbeef);
1607 ret
= GetProcessVersion(0);
1608 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1610 SetLastError(0xdeadbeef);
1611 ret
= GetProcessVersion(GetCurrentProcessId());
1612 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1614 memset(&si
, 0, sizeof(si
));
1616 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1617 si
.wShowWindow
= SW_HIDE
;
1618 SetLastError(0xdeadbeef);
1619 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1620 ok(ret
, "CreateProcess error %u\n", GetLastError());
1622 SetLastError(0xdeadbeef);
1623 ret
= GetProcessVersion(pi
.dwProcessId
);
1624 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1626 SetLastError(0xdeadbeef);
1627 ret
= TerminateProcess(pi
.hProcess
, 0);
1628 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1630 CloseHandle(pi
.hProcess
);
1631 CloseHandle(pi
.hThread
);
1634 static void test_GetProcessImageFileNameA(void)
1637 CHAR process
[MAX_PATH
];
1638 static const char harddisk
[] = "\\Device\\HarddiskVolume";
1640 if (!pK32GetProcessImageFileNameA
)
1642 win_skip("K32GetProcessImageFileNameA is unavailable\n");
1646 /* callers must guess the buffer size */
1647 SetLastError(0xdeadbeef);
1648 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), NULL
, 0);
1649 ok(!rc
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
1650 "K32GetProcessImageFileNameA(no buffer): returned %u, le=%u\n", rc
, GetLastError());
1653 rc
= pK32GetProcessImageFileNameA(GetCurrentProcess(), process
, sizeof(process
));
1654 expect_eq_d(rc
, lstrlenA(process
));
1655 if (strncmp(process
, harddisk
, lstrlenA(harddisk
)))
1657 todo_wine
win_skip("%s is probably on a network share, skipping tests\n", process
);
1661 if (!pQueryFullProcessImageNameA
)
1662 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1665 CHAR image
[MAX_PATH
];
1668 length
= sizeof(image
);
1669 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), PROCESS_NAME_NATIVE
, image
, &length
));
1670 expect_eq_d(length
, lstrlenA(image
));
1671 ok(lstrcmpiA(process
, image
) == 0, "expected '%s' to be equal to '%s'\n", process
, image
);
1675 static void test_QueryFullProcessImageNameA(void)
1677 #define INIT_STR "Just some words"
1679 CHAR buf
[MAX_PATH
], module
[MAX_PATH
];
1681 if (!pQueryFullProcessImageNameA
)
1683 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1688 SetLastError(0); /* old Windows don't reset it on success */
1689 size
= GetModuleFileNameA(NULL
, module
, sizeof(module
));
1690 ok(size
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
, "GetModuleFileName failed: %u le=%u\n", size
, GetLastError());
1692 /* get the buffer length without \0 terminator */
1693 length
= sizeof(buf
);
1694 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1695 expect_eq_d(length
, lstrlenA(buf
));
1696 ok((buf
[0] == '\\' && buf
[1] == '\\') ||
1697 lstrcmpiA(buf
, module
) == 0, "expected %s to match %s\n", buf
, module
);
1699 /* when the buffer is too small
1700 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1701 * - the size variable is not modified
1702 * tested with the biggest too small size
1705 sprintf(buf
,INIT_STR
);
1706 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1707 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1708 expect_eq_d(length
, size
);
1709 expect_eq_s(INIT_STR
, buf
);
1711 /* retest with smaller buffer size
1714 sprintf(buf
,INIT_STR
);
1715 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1716 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1717 expect_eq_d(4, size
);
1718 expect_eq_s(INIT_STR
, buf
);
1720 /* this is a difference between the ascii and the unicode version
1721 * the unicode version crashes when the size is big enough to hold
1722 * the result while the ascii version throws an error
1725 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1726 expect_eq_d(1024, size
);
1727 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1730 static void test_QueryFullProcessImageNameW(void)
1733 WCHAR module_name
[1024], device
[1024];
1734 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
1738 if (!pQueryFullProcessImageNameW
)
1740 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1744 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1746 /* GetCurrentProcess pseudo-handle */
1747 size
= sizeof(buf
) / sizeof(buf
[0]);
1748 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
1749 expect_eq_d(lstrlenW(buf
), size
);
1750 expect_eq_ws_i(buf
, module_name
);
1752 hSelf
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1754 size
= sizeof(buf
) / sizeof(buf
[0]);
1755 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1756 expect_eq_d(lstrlenW(buf
), size
);
1757 expect_eq_ws_i(buf
, module_name
);
1759 /* Buffer too small */
1760 size
= lstrlenW(module_name
)/2;
1761 lstrcpyW(buf
, deviceW
);
1762 SetLastError(0xdeadbeef);
1763 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1764 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1765 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1766 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
1768 /* Too small - not space for NUL terminator */
1769 size
= lstrlenW(module_name
);
1770 SetLastError(0xdeadbeef);
1771 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1772 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
1773 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1777 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
1778 expect_eq_d(0, size
);
1779 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1781 /* Buffer too small */
1782 size
= lstrlenW(module_name
)/2;
1783 SetLastError(0xdeadbeef);
1784 lstrcpyW(buf
, module_name
);
1785 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1786 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1787 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1788 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
1792 size
= sizeof(buf
) / sizeof(buf
[0]);
1793 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
1794 expect_eq_d(lstrlenW(buf
), size
);
1795 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
1796 ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
1798 module_name
[2] = '\0';
1800 size
= QueryDosDeviceW(module_name
, device
, sizeof(device
)/sizeof(device
[0]));
1801 ok(size
, "QueryDosDeviceW failed: le=%u\n", GetLastError());
1802 len
= lstrlenW(device
);
1803 ok(size
>= len
+2, "expected %d to be greater than %d+2 = strlen(%s)\n", size
, len
, wine_dbgstr_w(device
));
1805 if (size
>= lstrlenW(buf
))
1807 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
1811 ok(buf
[len
] == '\\', "expected '%c' to be a '\\' in %s\n", buf
[len
], wine_dbgstr_w(module_name
));
1813 ok(lstrcmpiW(device
, buf
) == 0, "expected %s to match %s\n", wine_dbgstr_w(device
), wine_dbgstr_w(buf
));
1814 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));
1820 static void test_Handles(void)
1822 HANDLE handle
= GetCurrentProcess();
1827 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
1828 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
1829 "invalid current process handle %p\n", handle
);
1830 ret
= GetExitCodeProcess( handle
, &code
);
1831 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1833 /* truncated handle */
1834 SetLastError( 0xdeadbeef );
1835 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
1836 ret
= GetExitCodeProcess( handle
, &code
);
1837 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1838 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1839 /* sign-extended handle */
1840 SetLastError( 0xdeadbeef );
1841 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
1842 ret
= GetExitCodeProcess( handle
, &code
);
1843 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1844 /* invalid high-word */
1845 SetLastError( 0xdeadbeef );
1846 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
1847 ret
= GetExitCodeProcess( handle
, &code
);
1848 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1849 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1852 handle
= GetStdHandle( STD_ERROR_HANDLE
);
1853 ok( handle
!= 0, "handle %p\n", handle
);
1854 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
1855 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1856 SetStdHandle( STD_ERROR_HANDLE
, h3
);
1857 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
1858 h2
= GetStdHandle( STD_ERROR_HANDLE
);
1860 broken( h2
== h3
) || /* nt4, w2k */
1861 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
1862 "wrong handle %p/%p\n", h2
, h3
);
1863 SetStdHandle( STD_ERROR_HANDLE
, handle
);
1866 static void test_SystemInfo(void)
1868 SYSTEM_INFO si
, nsi
;
1871 if (!pGetNativeSystemInfo
)
1873 win_skip("GetNativeSystemInfo is not available\n");
1877 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
1880 pGetNativeSystemInfo(&nsi
);
1883 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
1885 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
1886 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
1887 S(U(nsi
)).wProcessorArchitecture
);
1888 ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
,
1889 "Expected PROCESSOR_AMD_X8664, got %d\n",
1890 nsi
.dwProcessorType
);
1895 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
1896 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
1897 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
1898 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
1899 "Expected no difference for dwProcessorType, got %d and %d\n",
1900 si
.dwProcessorType
, nsi
.dwProcessorType
);
1904 static void test_RegistryQuota(void)
1907 DWORD max_quota
, used_quota
;
1909 if (!pGetSystemRegistryQuota
)
1911 win_skip("GetSystemRegistryQuota is not available\n");
1915 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
1917 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
1919 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
1921 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
1923 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
1925 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
1927 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
1929 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
1932 static void test_TerminateProcess(void)
1934 static char cmdline
[] = "winver.exe";
1935 PROCESS_INFORMATION pi
;
1938 HANDLE dummy
, thread
;
1940 memset(&si
, 0, sizeof(si
));
1942 SetLastError(0xdeadbeef);
1943 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &si
, &pi
);
1944 ok(ret
, "CreateProcess error %u\n", GetLastError());
1946 SetLastError(0xdeadbeef);
1947 thread
= CreateRemoteThread(pi
.hProcess
, NULL
, 0, (void *)0xdeadbeef, NULL
, CREATE_SUSPENDED
, &ret
);
1948 ok(thread
!= 0, "CreateRemoteThread error %d\n", GetLastError());
1950 /* create a not closed thread handle duplicate in the target process */
1951 SetLastError(0xdeadbeef);
1952 ret
= DuplicateHandle(GetCurrentProcess(), thread
, pi
.hProcess
, &dummy
,
1953 0, FALSE
, DUPLICATE_SAME_ACCESS
);
1954 ok(ret
, "DuplicateHandle error %u\n", GetLastError());
1956 SetLastError(0xdeadbeef);
1957 ret
= TerminateThread(thread
, 0);
1958 ok(ret
, "TerminateThread error %u\n", GetLastError());
1959 CloseHandle(thread
);
1961 SetLastError(0xdeadbeef);
1962 ret
= TerminateProcess(pi
.hProcess
, 0);
1963 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1965 CloseHandle(pi
.hProcess
);
1966 CloseHandle(pi
.hThread
);
1969 static void test_DuplicateHandle(void)
1971 char path
[MAX_PATH
], file_name
[MAX_PATH
];
1972 HANDLE f
, fmin
, out
;
1976 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
1977 GetCurrentProcess(), &out
, 0, FALSE
,
1978 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
1979 ok(r
, "DuplicateHandle error %u\n", GetLastError());
1980 r
= GetHandleInformation(out
, &info
);
1981 ok(r
, "GetHandleInformation error %u\n", GetLastError());
1982 ok(info
== 0, "info = %x\n", info
);
1983 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
1986 r
= DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
1987 GetCurrentProcess(), &out
, 0, TRUE
,
1988 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
1989 ok(r
, "DuplicateHandle error %u\n", GetLastError());
1990 r
= GetHandleInformation(out
, &info
);
1991 ok(r
, "GetHandleInformation error %u\n", GetLastError());
1992 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
1993 ok(out
!= GetCurrentProcess(), "out = GetCurrentProcess()\n");
1996 GetTempPathA(MAX_PATH
, path
);
1997 GetTempFileNameA(path
, "wt", 0, file_name
);
1998 f
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
1999 if (f
== INVALID_HANDLE_VALUE
)
2001 ok(0, "could not create %s\n", file_name
);
2005 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2006 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2007 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2008 ok(f
== out
, "f != out\n");
2009 r
= GetHandleInformation(out
, &info
);
2010 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2011 ok(info
== 0, "info = %x\n", info
);
2013 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2014 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2015 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2016 ok(f
== out
, "f != out\n");
2017 r
= GetHandleInformation(out
, &info
);
2018 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2019 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2021 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, HANDLE_FLAG_PROTECT_FROM_CLOSE
);
2022 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2023 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2024 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2025 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2026 ok(f
!= out
, "f == out\n");
2027 r
= GetHandleInformation(out
, &info
);
2028 ok(r
, "GetHandleInformation error %u\n", GetLastError());
2029 ok(info
== HANDLE_FLAG_INHERIT
, "info = %x\n", info
);
2030 r
= SetHandleInformation(f
, HANDLE_FLAG_PROTECT_FROM_CLOSE
, 0);
2031 ok(r
, "SetHandleInformation error %u\n", GetLastError());
2033 /* Test if DuplicateHandle allocates first free handle */
2044 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2045 0, TRUE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2046 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2047 ok(f
== out
, "f != out\n");
2049 DeleteFileA(file_name
);
2051 f
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
2054 skip("DuplicateHandle on console handle\n");
2059 r
= DuplicateHandle(GetCurrentProcess(), f
, GetCurrentProcess(), &out
,
2060 0, FALSE
, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
2061 ok(r
, "DuplicateHandle error %u\n", GetLastError());
2062 todo_wine
ok(f
!= out
, "f == out\n");
2069 ok(b
, "Basic init of CreateProcess test\n");
2074 doChild(myARGV
[2], (myARGC
== 3) ? NULL
: myARGV
[3]);
2077 test_TerminateProcess();
2083 test_DebuggingFlag();
2087 test_GetProcessVersion();
2088 test_GetProcessImageFileNameA();
2089 test_QueryFullProcessImageNameA();
2090 test_QueryFullProcessImageNameW();
2093 test_RegistryQuota();
2094 test_DuplicateHandle();
2095 /* things that can be tested:
2096 * lookup: check the way program to be executed is searched
2097 * handles: check the handle inheritance stuff (+sec options)
2098 * console: check if console creation parameters work