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 #define expect_eq_d(expected, actual) \
40 int value = (actual); \
41 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
44 #define expect_eq_s(expected, actual) \
46 LPCSTR value = (actual); \
47 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
50 #define expect_eq_ws_i(expected, actual) \
52 LPCWSTR value = (actual); \
53 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
54 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
57 static HINSTANCE hkernel32
;
58 static void (WINAPI
*pGetNativeSystemInfo
)(LPSYSTEM_INFO
);
59 static BOOL (WINAPI
*pGetSystemRegistryQuota
)(PDWORD
, PDWORD
);
60 static BOOL (WINAPI
*pIsWow64Process
)(HANDLE
,PBOOL
);
61 static LPVOID (WINAPI
*pVirtualAllocEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
, DWORD
);
62 static BOOL (WINAPI
*pVirtualFreeEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
);
63 static BOOL (WINAPI
*pQueryFullProcessImageNameA
)(HANDLE hProcess
, DWORD dwFlags
, LPSTR lpExeName
, PDWORD lpdwSize
);
64 static BOOL (WINAPI
*pQueryFullProcessImageNameW
)(HANDLE hProcess
, DWORD dwFlags
, LPWSTR lpExeName
, PDWORD lpdwSize
);
66 /* ############################### */
67 static char base
[MAX_PATH
];
68 static char selfname
[MAX_PATH
];
70 static char resfile
[MAX_PATH
];
75 /* As some environment variables get very long on Unix, we only test for
76 * the first 127 bytes.
77 * Note that increasing this value past 256 may exceed the buffer size
78 * limitations of the *Profile functions (at least on Wine).
80 #define MAX_LISTED_ENV_VAR 128
82 /* ---------------- portable memory allocation thingie */
84 static char memory
[1024*256];
85 static char* memory_index
= memory
;
87 static char* grab_memory(size_t len
)
89 char* ret
= memory_index
;
93 assert(memory_index
<= memory
+ sizeof(memory
));
97 static void release_memory(void)
99 memory_index
= memory
;
102 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
104 static const char* encodeA(const char* str
)
110 len
= strlen(str
) + 1;
111 ptr
= grab_memory(len
* 2 + 1);
112 for (i
= 0; i
< len
; i
++)
113 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
118 static const char* encodeW(const WCHAR
* str
)
124 len
= lstrlenW(str
) + 1;
125 ptr
= grab_memory(len
* 4 + 1);
127 for (i
= 0; i
< len
; i
++)
128 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
133 static unsigned decode_char(char c
)
135 if (c
>= '0' && c
<= '9') return c
- '0';
136 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
137 assert(c
>= 'A' && c
<= 'F');
141 static char* decodeA(const char* str
)
146 len
= strlen(str
) / 2;
147 if (!len
--) return NULL
;
148 ptr
= grab_memory(len
+ 1);
149 for (i
= 0; i
< len
; i
++)
150 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
155 /* This will be needed to decode Unicode strings saved by the child process
156 * when we test Unicode functions.
158 static WCHAR
* decodeW(const char* str
)
164 len
= strlen(str
) / 4;
165 if (!len
--) return NULL
;
166 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
167 for (i
= 0; i
< len
; i
++)
168 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
169 (decode_char(str
[4 * i
+ 1]) << 8) |
170 (decode_char(str
[4 * i
+ 2]) << 4) |
171 (decode_char(str
[4 * i
+ 3]) << 0);
176 /******************************************************************
179 * generates basic information like:
180 * base: absolute path to curr dir
181 * selfname: the way to reinvoke ourselves
182 * exename: executable without the path
183 * function-pointers, which are not implemented in all windows versions
185 static int init(void)
189 myARGC
= winetest_get_mainargs( &myARGV
);
190 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return 0;
191 strcpy(selfname
, myARGV
[0]);
193 /* Strip the path of selfname */
194 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
195 else exename
= selfname
;
197 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
199 hkernel32
= GetModuleHandleA("kernel32");
200 pGetNativeSystemInfo
= (void *) GetProcAddress(hkernel32
, "GetNativeSystemInfo");
201 pGetSystemRegistryQuota
= (void *) GetProcAddress(hkernel32
, "GetSystemRegistryQuota");
202 pIsWow64Process
= (void *) GetProcAddress(hkernel32
, "IsWow64Process");
203 pVirtualAllocEx
= (void *) GetProcAddress(hkernel32
, "VirtualAllocEx");
204 pVirtualFreeEx
= (void *) GetProcAddress(hkernel32
, "VirtualFreeEx");
205 pQueryFullProcessImageNameA
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameA");
206 pQueryFullProcessImageNameW
= (void *) GetProcAddress(hkernel32
, "QueryFullProcessImageNameW");
210 /******************************************************************
213 * generates an absolute file_name for temporary file
216 static void get_file_name(char* buf
)
221 GetTempPathA(sizeof(path
), path
);
222 GetTempFileNameA(path
, "wt", 0, buf
);
225 /******************************************************************
226 * static void childPrintf
229 static void childPrintf(HANDLE h
, const char* fmt
, ...)
232 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
235 va_start(valist
, fmt
);
236 vsprintf(buffer
, fmt
, valist
);
238 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
242 /******************************************************************
245 * output most of the information in the child process
247 static void doChild(const char* file
, const char* option
)
252 char *ptrA
, *ptrA_save
;
253 WCHAR
*ptrW
, *ptrW_save
;
255 WCHAR bufW
[MAX_PATH
];
256 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
259 if (hFile
== INVALID_HANDLE_VALUE
) return;
261 /* output of startup info (Ansi) */
262 GetStartupInfoA(&siA
);
264 "[StartupInfoA]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
265 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
266 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
267 "dwFlags=%lu\nwShowWindow=%u\n"
268 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
269 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
270 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
271 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
272 siA
.dwFlags
, siA
.wShowWindow
,
273 (DWORD_PTR
)siA
.hStdInput
, (DWORD_PTR
)siA
.hStdOutput
, (DWORD_PTR
)siA
.hStdError
);
275 /* since GetStartupInfoW is only implemented in win2k,
276 * zero out before calling so we can notice the difference
278 memset(&siW
, 0, sizeof(siW
));
279 GetStartupInfoW(&siW
);
281 "[StartupInfoW]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
282 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
283 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
284 "dwFlags=%lu\nwShowWindow=%u\n"
285 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
286 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
287 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
288 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
289 siW
.dwFlags
, siW
.wShowWindow
,
290 (DWORD_PTR
)siW
.hStdInput
, (DWORD_PTR
)siW
.hStdOutput
, (DWORD_PTR
)siW
.hStdError
);
293 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
294 for (i
= 0; i
< myARGC
; i
++)
296 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
298 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
304 /* this is part of shell32... and should be tested there */
305 argvW
= CommandLineToArgvW(GetCommandLineW(), &argcW
);
306 for (i
= 0; i
< argcW
; i
++)
308 childPrintf(hFile
, "argvW%d=%s\n", i
, encodeW(argvW
[i
]));
311 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
313 /* output of environment (Ansi) */
314 ptrA_save
= ptrA
= GetEnvironmentStringsA();
317 char env_var
[MAX_LISTED_ENV_VAR
];
319 childPrintf(hFile
, "[EnvironmentA]\n");
323 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
324 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
326 ptrA
+= strlen(ptrA
) + 1;
328 childPrintf(hFile
, "len=%d\n\n", i
);
329 FreeEnvironmentStringsA(ptrA_save
);
332 /* output of environment (Unicode) */
333 ptrW_save
= ptrW
= GetEnvironmentStringsW();
336 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
338 childPrintf(hFile
, "[EnvironmentW]\n");
342 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
343 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
344 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
346 ptrW
+= lstrlenW(ptrW
) + 1;
348 childPrintf(hFile
, "len=%d\n\n", i
);
349 FreeEnvironmentStringsW(ptrW_save
);
352 childPrintf(hFile
, "[Misc]\n");
353 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
354 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
355 if (GetCurrentDirectoryW(sizeof(bufW
) / sizeof(bufW
[0]), bufW
))
356 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
357 childPrintf(hFile
, "\n");
359 if (option
&& strcmp(option
, "console") == 0)
361 CONSOLE_SCREEN_BUFFER_INFO sbi
;
362 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
363 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
364 DWORD modeIn
, modeOut
;
366 childPrintf(hFile
, "[Console]\n");
367 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
369 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
370 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
371 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
372 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
373 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
374 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
376 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
377 GetConsoleCP(), GetConsoleOutputCP());
378 if (GetConsoleMode(hConIn
, &modeIn
))
379 childPrintf(hFile
, "InputMode=%ld\n", modeIn
);
380 if (GetConsoleMode(hConOut
, &modeOut
))
381 childPrintf(hFile
, "OutputMode=%ld\n", modeOut
);
383 /* now that we have written all relevant information, let's change it */
384 SetLastError(0xdeadbeef);
385 ret
= SetConsoleCP(1252);
386 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
388 win_skip("Setting the codepage is not implemented\n");
392 ok(ret
, "Setting CP\n");
393 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
396 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
397 ok( ret
, "Setting mode (%d)\n", GetLastError());
398 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
399 ok( ret
, "Setting mode (%d)\n", GetLastError());
400 sbi
.dwCursorPosition
.X
^= 1;
401 sbi
.dwCursorPosition
.Y
^= 1;
402 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
403 ok( ret
, "Setting cursor position (%d)\n", GetLastError());
405 if (option
&& strcmp(option
, "stdhandle") == 0)
407 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
408 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
410 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
415 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
416 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
417 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
421 if (option
&& strcmp(option
, "exit_code") == 0)
423 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
431 static char* getChildString(const char* sect
, const char* key
)
433 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
436 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
437 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
438 assert(!(strlen(buf
) & 1));
443 static WCHAR
* getChildStringW(const char* sect
, const char* key
)
445 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
448 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
449 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
450 assert(!(strlen(buf
) & 1));
455 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
456 * others... (windows uses stricmp while Un*x uses strcasecmp...)
458 static int wtstrcasecmp(const char* p1
, const char* p2
)
463 while (c1
== c2
&& c1
)
465 c1
= *p1
++; c2
= *p2
++;
468 c1
= toupper(c1
); c2
= toupper(c2
);
474 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
476 if (!s1
&& !s2
) return 0;
479 return (sensitive
) ? strcmp(s1
, s2
) : wtstrcasecmp(s1
, s2
);
482 static void ok_child_string( int line
, const char *sect
, const char *key
,
483 const char *expect
, int sensitive
)
485 char* result
= getChildString( sect
, key
);
486 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
487 sect
, key
, expect
? expect
: "(null)", result
);
490 static void ok_child_stringWA( int line
, const char *sect
, const char *key
,
491 const char *expect
, int sensitive
)
496 WCHAR
* result
= getChildStringW( sect
, key
);
498 len
= MultiByteToWideChar( CP_ACP
, 0, expect
, -1, NULL
, 0);
499 expectW
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(WCHAR
));
500 MultiByteToWideChar( CP_ACP
, 0, expect
, -1, expectW
, len
);
502 len
= WideCharToMultiByte( CP_ACP
, 0, result
, -1, NULL
, 0, NULL
, NULL
);
503 resultA
= HeapAlloc(GetProcessHeap(),0,len
*sizeof(CHAR
));
504 WideCharToMultiByte( CP_ACP
, 0, result
, -1, resultA
, len
, NULL
, NULL
);
507 ok_(__FILE__
, line
)( lstrcmpW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
508 sect
, key
, expect
? expect
: "(null)", resultA
);
510 ok_(__FILE__
, line
)( lstrcmpiW(result
, expectW
) == 0, "%s:%s expected '%s', got '%s'\n",
511 sect
, key
, expect
? expect
: "(null)", resultA
);
512 HeapFree(GetProcessHeap(),0,expectW
);
513 HeapFree(GetProcessHeap(),0,resultA
);
516 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
517 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
518 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
520 /* using !expect ensures that the test will fail if the sect/key isn't present
523 #define okChildInt(sect, key, expect) \
525 UINT result = GetPrivateProfileIntA((sect), (key), !(expect), resfile); \
526 ok(result == expect, "%s:%s expected %u, but got %u\n", (sect), (key), (UINT)(expect), result); \
529 static void test_Startup(void)
531 char buffer
[MAX_PATH
];
532 PROCESS_INFORMATION info
;
533 STARTUPINFOA startup
,si
;
535 static CHAR title
[] = "I'm the title string",
536 desktop
[] = "winsta0\\default",
539 /* let's start simplistic */
540 memset(&startup
, 0, sizeof(startup
));
541 startup
.cb
= sizeof(startup
);
542 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
543 startup
.wShowWindow
= SW_SHOWNORMAL
;
545 get_file_name(resfile
);
546 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
547 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
548 /* wait for child to terminate */
549 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
550 /* child process has changed result file, so let profile functions know about it */
551 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
553 GetStartupInfoA(&si
);
554 okChildInt("StartupInfoA", "cb", startup
.cb
);
555 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
556 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
557 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
558 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
559 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
560 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
561 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
562 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
563 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
564 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
566 assert(DeleteFileA(resfile
) != 0);
568 /* not so simplistic now */
569 memset(&startup
, 0, sizeof(startup
));
570 startup
.cb
= sizeof(startup
);
571 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
572 startup
.wShowWindow
= SW_SHOWNORMAL
;
573 startup
.lpTitle
= title
;
574 startup
.lpDesktop
= desktop
;
575 startup
.dwXCountChars
= 0x12121212;
576 startup
.dwYCountChars
= 0x23232323;
577 startup
.dwX
= 0x34343434;
578 startup
.dwY
= 0x45454545;
579 startup
.dwXSize
= 0x56565656;
580 startup
.dwYSize
= 0x67676767;
581 startup
.dwFillAttribute
= 0xA55A;
583 get_file_name(resfile
);
584 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
585 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
586 /* wait for child to terminate */
587 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
588 /* child process has changed result file, so let profile functions know about it */
589 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
591 okChildInt("StartupInfoA", "cb", startup
.cb
);
592 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
593 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
594 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
595 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
596 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
597 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
598 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
599 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
600 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
601 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
602 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
604 assert(DeleteFileA(resfile
) != 0);
606 /* not so simplistic now */
607 memset(&startup
, 0, sizeof(startup
));
608 startup
.cb
= sizeof(startup
);
609 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
610 startup
.wShowWindow
= SW_SHOWNORMAL
;
611 startup
.lpTitle
= title
;
612 startup
.lpDesktop
= NULL
;
613 startup
.dwXCountChars
= 0x12121212;
614 startup
.dwYCountChars
= 0x23232323;
615 startup
.dwX
= 0x34343434;
616 startup
.dwY
= 0x45454545;
617 startup
.dwXSize
= 0x56565656;
618 startup
.dwYSize
= 0x67676767;
619 startup
.dwFillAttribute
= 0xA55A;
621 get_file_name(resfile
);
622 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
623 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
624 /* wait for child to terminate */
625 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
626 /* child process has changed result file, so let profile functions know about it */
627 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
629 okChildInt("StartupInfoA", "cb", startup
.cb
);
630 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
631 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
632 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
633 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
634 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
635 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
636 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
637 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
638 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
639 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
640 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
642 assert(DeleteFileA(resfile
) != 0);
644 /* not so simplistic now */
645 memset(&startup
, 0, sizeof(startup
));
646 startup
.cb
= sizeof(startup
);
647 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
648 startup
.wShowWindow
= SW_SHOWNORMAL
;
649 startup
.lpTitle
= title
;
650 startup
.lpDesktop
= empty
;
651 startup
.dwXCountChars
= 0x12121212;
652 startup
.dwYCountChars
= 0x23232323;
653 startup
.dwX
= 0x34343434;
654 startup
.dwY
= 0x45454545;
655 startup
.dwXSize
= 0x56565656;
656 startup
.dwYSize
= 0x67676767;
657 startup
.dwFillAttribute
= 0xA55A;
659 get_file_name(resfile
);
660 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
661 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
662 /* wait for child to terminate */
663 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
664 /* child process has changed result file, so let profile functions know about it */
665 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
667 okChildInt("StartupInfoA", "cb", startup
.cb
);
668 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
669 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
670 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
671 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
672 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
673 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
674 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
675 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
676 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
677 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
678 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
680 assert(DeleteFileA(resfile
) != 0);
682 /* not so simplistic now */
683 memset(&startup
, 0, sizeof(startup
));
684 startup
.cb
= sizeof(startup
);
685 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
686 startup
.wShowWindow
= SW_SHOWNORMAL
;
687 startup
.lpTitle
= NULL
;
688 startup
.lpDesktop
= desktop
;
689 startup
.dwXCountChars
= 0x12121212;
690 startup
.dwYCountChars
= 0x23232323;
691 startup
.dwX
= 0x34343434;
692 startup
.dwY
= 0x45454545;
693 startup
.dwXSize
= 0x56565656;
694 startup
.dwYSize
= 0x67676767;
695 startup
.dwFillAttribute
= 0xA55A;
697 get_file_name(resfile
);
698 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
699 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
700 /* wait for child to terminate */
701 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
702 /* child process has changed result file, so let profile functions know about it */
703 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
705 okChildInt("StartupInfoA", "cb", startup
.cb
);
706 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
707 result
= getChildString( "StartupInfoA", "lpTitle" );
708 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
709 "expected '%s' or null, got '%s'\n", selfname
, result
);
710 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
711 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
712 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
713 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
714 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
715 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
716 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
717 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
718 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
720 assert(DeleteFileA(resfile
) != 0);
722 /* not so simplistic now */
723 memset(&startup
, 0, sizeof(startup
));
724 startup
.cb
= sizeof(startup
);
725 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
726 startup
.wShowWindow
= SW_SHOWNORMAL
;
727 startup
.lpTitle
= empty
;
728 startup
.lpDesktop
= desktop
;
729 startup
.dwXCountChars
= 0x12121212;
730 startup
.dwYCountChars
= 0x23232323;
731 startup
.dwX
= 0x34343434;
732 startup
.dwY
= 0x45454545;
733 startup
.dwXSize
= 0x56565656;
734 startup
.dwYSize
= 0x67676767;
735 startup
.dwFillAttribute
= 0xA55A;
737 get_file_name(resfile
);
738 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
739 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
740 /* wait for child to terminate */
741 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
742 /* child process has changed result file, so let profile functions know about it */
743 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
745 okChildInt("StartupInfoA", "cb", startup
.cb
);
746 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
747 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
748 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
749 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
750 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
751 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
752 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
753 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
754 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
755 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
756 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
758 assert(DeleteFileA(resfile
) != 0);
760 /* not so simplistic now */
761 memset(&startup
, 0, sizeof(startup
));
762 startup
.cb
= sizeof(startup
);
763 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
764 startup
.wShowWindow
= SW_SHOWNORMAL
;
765 startup
.lpTitle
= empty
;
766 startup
.lpDesktop
= empty
;
767 startup
.dwXCountChars
= 0x12121212;
768 startup
.dwYCountChars
= 0x23232323;
769 startup
.dwX
= 0x34343434;
770 startup
.dwY
= 0x45454545;
771 startup
.dwXSize
= 0x56565656;
772 startup
.dwYSize
= 0x67676767;
773 startup
.dwFillAttribute
= 0xA55A;
775 get_file_name(resfile
);
776 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
777 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
778 /* wait for child to terminate */
779 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
780 /* child process has changed result file, so let profile functions know about it */
781 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
783 okChildInt("StartupInfoA", "cb", startup
.cb
);
784 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
785 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
786 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
787 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
788 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
789 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
790 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
791 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
792 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
793 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
794 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
796 assert(DeleteFileA(resfile
) != 0);
798 /* TODO: test for A/W and W/A and W/W */
801 static void test_CommandLine(void)
803 char buffer
[MAX_PATH
], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
804 char buffer2
[MAX_PATH
];
805 PROCESS_INFORMATION info
;
806 STARTUPINFOA startup
;
809 memset(&startup
, 0, sizeof(startup
));
810 startup
.cb
= sizeof(startup
);
811 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
812 startup
.wShowWindow
= SW_SHOWNORMAL
;
815 get_file_name(resfile
);
816 sprintf(buffer
, "\"%s\" tests/process.c \"%s\" \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
817 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
818 /* wait for child to terminate */
819 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
820 /* child process has changed result file, so let profile functions know about it */
821 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
823 okChildInt("Arguments", "argcA", 4);
824 okChildString("Arguments", "argvA3", "C:\\Program Files\\my nice app.exe");
825 okChildString("Arguments", "argvA4", NULL
);
826 okChildString("Arguments", "CommandLineA", buffer
);
828 assert(DeleteFileA(resfile
) != 0);
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 \"%s\" \"a\\\"b\\\\\" c\\\" d", 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", 6);
845 okChildString("Arguments", "argvA3", "a\"b\\");
846 okChildString("Arguments", "argvA4", "c\"");
847 okChildString("Arguments", "argvA5", "d");
848 okChildString("Arguments", "argvA6", NULL
);
849 okChildString("Arguments", "CommandLineA", buffer
);
851 assert(DeleteFileA(resfile
) != 0);
853 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
854 get_file_name(resfile
);
855 /* Use exename to avoid buffer containing things like 'C:' */
856 sprintf(buffer
, "./%s tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
857 SetLastError(0xdeadbeef);
858 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
859 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
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
);
864 sprintf(buffer
, "./%s", exename
);
865 okChildString("Arguments", "argvA0", buffer
);
867 assert(DeleteFileA(resfile
) != 0);
869 get_file_name(resfile
);
870 /* Use exename to avoid buffer containing things like 'C:' */
871 sprintf(buffer
, ".\\%s tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
872 SetLastError(0xdeadbeef);
873 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
874 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
875 /* wait for child to terminate */
876 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
877 /* child process has changed result file, so let profile functions know about it */
878 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
879 sprintf(buffer
, ".\\%s", exename
);
880 okChildString("Arguments", "argvA0", buffer
);
882 assert(DeleteFileA(resfile
) != 0);
884 get_file_name(resfile
);
885 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
886 assert ( lpFilePart
!= 0);
887 *(lpFilePart
-1 ) = 0;
888 p
= strrchr(fullpath
, '\\');
889 /* Use exename to avoid buffer containing things like 'C:' */
890 if (p
) sprintf(buffer
, "..%s/%s tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", p
, exename
, resfile
);
891 else sprintf(buffer
, "./%s tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
892 SetLastError(0xdeadbeef);
893 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
894 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
895 /* wait for child to terminate */
896 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
897 /* child process has changed result file, so let profile functions know about it */
898 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
899 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
900 else sprintf(buffer
, "./%s", exename
);
901 okChildString("Arguments", "argvA0", buffer
);
903 assert(DeleteFileA(resfile
) != 0);
906 get_file_name(resfile
);
907 GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
908 assert ( lpFilePart
!= 0);
909 *(lpFilePart
-1 ) = 0;
910 p
= strrchr(fullpath
, '\\');
911 /* Use exename to avoid buffer containing things like 'C:' */
912 if (p
) sprintf(buffer
, "..%s/%s", p
, exename
);
913 else sprintf(buffer
, "./%s", exename
);
914 sprintf(buffer2
, "dummy tests/process.c \"%s\" \"a\\\"b\\\\\" c\\\" d", resfile
);
915 SetLastError(0xdeadbeef);
916 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
917 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
918 /* wait for child to terminate */
919 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
920 /* child process has changed result file, so let profile functions know about it */
921 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
922 sprintf(buffer
, "tests/process.c %s", resfile
);
923 okChildString("Arguments", "argvA0", "dummy");
924 okChildString("Arguments", "CommandLineA", buffer2
);
925 okChildStringWA("Arguments", "CommandLineW", buffer2
);
927 assert(DeleteFileA(resfile
) != 0);
929 if (0) /* Test crashes on NT-based Windows. */
931 /* Test NULL application name and command line parameters. */
932 SetLastError(0xdeadbeef);
933 ret
= CreateProcessA(NULL
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
934 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
935 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
936 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
941 /* Test empty application name parameter. */
942 SetLastError(0xdeadbeef);
943 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
944 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
945 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
946 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
947 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
948 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
952 /* Test empty application name and command line parameters. */
953 SetLastError(0xdeadbeef);
954 ret
= CreateProcessA(buffer
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
955 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
956 ok(GetLastError() == ERROR_PATH_NOT_FOUND
||
957 broken(GetLastError() == ERROR_FILE_NOT_FOUND
) /* Win9x/WinME */ ||
958 broken(GetLastError() == ERROR_ACCESS_DENIED
) /* Win98 */,
959 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
961 /* Test empty command line parameter. */
962 SetLastError(0xdeadbeef);
963 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
964 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
965 ok(GetLastError() == ERROR_FILE_NOT_FOUND
||
966 GetLastError() == ERROR_PATH_NOT_FOUND
/* NT4 */ ||
967 GetLastError() == ERROR_BAD_PATHNAME
/* Win98 */ ||
968 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7 */,
969 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
971 strcpy(buffer
, "doesnotexist.exe");
972 strcpy(buffer2
, "does not exist.exe");
974 /* Test nonexistent application name. */
975 SetLastError(0xdeadbeef);
976 ret
= CreateProcessA(buffer
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
977 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
978 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
980 SetLastError(0xdeadbeef);
981 ret
= CreateProcessA(buffer2
, NULL
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
982 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
983 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
985 /* Test nonexistent command line parameter. */
986 SetLastError(0xdeadbeef);
987 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
988 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
989 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
991 SetLastError(0xdeadbeef);
992 ret
= CreateProcessA(NULL
, buffer2
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
993 ok(!ret
, "CreateProcessA unexpectedly succeeded\n");
994 ok(GetLastError() == ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
997 static void test_Directory(void)
999 char buffer
[MAX_PATH
];
1000 PROCESS_INFORMATION info
;
1001 STARTUPINFOA startup
;
1002 char windir
[MAX_PATH
];
1003 static CHAR cmdline
[] = "winver.exe";
1005 memset(&startup
, 0, sizeof(startup
));
1006 startup
.cb
= sizeof(startup
);
1007 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1008 startup
.wShowWindow
= SW_SHOWNORMAL
;
1011 get_file_name(resfile
);
1012 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1013 GetWindowsDirectoryA( windir
, sizeof(windir
) );
1014 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
1015 /* wait for child to terminate */
1016 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1017 /* child process has changed result file, so let profile functions know about it */
1018 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1020 okChildIString("Misc", "CurrDirA", windir
);
1022 assert(DeleteFileA(resfile
) != 0);
1024 /* search PATH for the exe if directory is NULL */
1025 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1026 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
1028 /* if any directory is provided, don't search PATH, error on bad directory */
1029 SetLastError(0xdeadbeef);
1030 memset(&info
, 0, sizeof(info
));
1031 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
1032 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
1033 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1034 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
1037 static BOOL
is_str_env_drive_dir(const char* str
)
1039 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
1040 str
[3] == '=' && str
[4] == str
[1];
1043 /* compared expected child's environment (in gesA) from actual
1044 * environment our child got
1046 static void cmpEnvironment(const char* gesA
)
1054 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
1056 /* now look each parent env in child */
1057 if ((ptrA
= gesA
) != NULL
)
1061 for (i
= 0; i
< clen
; i
++)
1063 sprintf(key
, "env%d", i
);
1064 res
= getChildString("EnvironmentA", key
);
1065 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
1069 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
1071 ptrA
+= strlen(ptrA
) + 1;
1075 /* and each child env in parent */
1076 for (i
= 0; i
< clen
; i
++)
1078 sprintf(key
, "env%d", i
);
1079 res
= getChildString("EnvironmentA", key
);
1080 if ((ptrA
= gesA
) != NULL
)
1084 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
1086 ptrA
+= strlen(ptrA
) + 1;
1088 if (!*ptrA
) ptrA
= NULL
;
1091 if (!is_str_env_drive_dir(res
))
1093 found
= ptrA
!= NULL
;
1094 ok(found
, "Child-env string %s isn't in parent process\n", res
);
1096 /* else => should also test we get the right per drive default directory here... */
1100 static void test_Environment(void)
1102 char buffer
[MAX_PATH
];
1103 PROCESS_INFORMATION info
;
1104 STARTUPINFOA startup
;
1112 memset(&startup
, 0, sizeof(startup
));
1113 startup
.cb
= sizeof(startup
);
1114 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1115 startup
.wShowWindow
= SW_SHOWNORMAL
;
1118 get_file_name(resfile
);
1119 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1120 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1121 /* wait for child to terminate */
1122 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1123 /* child process has changed result file, so let profile functions know about it */
1124 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1126 env
= GetEnvironmentStringsA();
1127 cmpEnvironment(env
);
1129 assert(DeleteFileA(resfile
) != 0);
1131 memset(&startup
, 0, sizeof(startup
));
1132 startup
.cb
= sizeof(startup
);
1133 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1134 startup
.wShowWindow
= SW_SHOWNORMAL
;
1137 get_file_name(resfile
);
1138 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1144 slen
= strlen(ptr
)+1;
1145 child_env_len
+= slen
;
1148 /* Add space for additional environment variables */
1149 child_env_len
+= 256;
1150 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
1153 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1154 ptr
+= strlen(ptr
) + 1;
1155 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1156 ptr
+= strlen(ptr
) + 1;
1157 strcpy(ptr
, "FOO=BAR");
1158 ptr
+= strlen(ptr
) + 1;
1159 strcpy(ptr
, "BAR=FOOBAR");
1160 ptr
+= strlen(ptr
) + 1;
1161 /* copy all existing variables except:
1163 * - PATH (already set above)
1164 * - the directory definitions (=[A-Z]:=)
1166 for (ptr2
= env
; *ptr2
; ptr2
+= strlen(ptr2
) + 1)
1168 if (strncmp(ptr2
, "PATH=", 5) != 0 &&
1169 strncmp(ptr2
, "WINELOADER=", 11) != 0 &&
1170 !is_str_env_drive_dir(ptr2
))
1173 ptr
+= strlen(ptr
) + 1;
1177 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1178 /* wait for child to terminate */
1179 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1180 /* child process has changed result file, so let profile functions know about it */
1181 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1183 cmpEnvironment(child_env
);
1185 HeapFree(GetProcessHeap(), 0, child_env
);
1186 FreeEnvironmentStringsA(env
);
1188 assert(DeleteFileA(resfile
) != 0);
1191 static void test_SuspendFlag(void)
1193 char buffer
[MAX_PATH
];
1194 PROCESS_INFORMATION info
;
1195 STARTUPINFOA startup
, us
;
1199 /* let's start simplistic */
1200 memset(&startup
, 0, sizeof(startup
));
1201 startup
.cb
= sizeof(startup
);
1202 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1203 startup
.wShowWindow
= SW_SHOWNORMAL
;
1205 get_file_name(resfile
);
1206 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1207 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1209 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1211 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1212 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1214 /* wait for child to terminate */
1215 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1216 /* child process has changed result file, so let profile functions know about it */
1217 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1219 GetStartupInfoA(&us
);
1221 okChildInt("StartupInfoA", "cb", startup
.cb
);
1222 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1223 result
= getChildString( "StartupInfoA", "lpTitle" );
1224 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1225 "expected '%s' or null, got '%s'\n", selfname
, result
);
1226 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1227 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1228 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1229 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1230 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1231 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1232 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1233 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1234 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1236 assert(DeleteFileA(resfile
) != 0);
1239 static void test_DebuggingFlag(void)
1241 char buffer
[MAX_PATH
];
1242 void *processbase
= NULL
;
1243 PROCESS_INFORMATION info
;
1244 STARTUPINFOA startup
, us
;
1249 /* let's start simplistic */
1250 memset(&startup
, 0, sizeof(startup
));
1251 startup
.cb
= sizeof(startup
);
1252 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1253 startup
.wShowWindow
= SW_SHOWNORMAL
;
1255 get_file_name(resfile
);
1256 sprintf(buffer
, "\"%s\" tests/process.c \"%s\"", selfname
, resfile
);
1257 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1259 /* get all startup events up to the entry point break exception */
1262 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1263 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1266 ok(de
.dwDebugEventCode
== CREATE_PROCESS_DEBUG_EVENT
,
1267 "first event: %d\n", de
.dwDebugEventCode
);
1268 processbase
= de
.u
.CreateProcessInfo
.lpBaseOfImage
;
1270 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1271 ok(de
.dwDebugEventCode
!= LOAD_DLL_DEBUG_EVENT
||
1272 de
.u
.LoadDll
.lpBaseOfDll
!= processbase
, "got LOAD_DLL for main module\n");
1273 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1275 ok(dbg
, "I have seen a debug event\n");
1276 /* wait for child to terminate */
1277 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1278 /* child process has changed result file, so let profile functions know about it */
1279 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1281 GetStartupInfoA(&us
);
1283 okChildInt("StartupInfoA", "cb", startup
.cb
);
1284 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1285 result
= getChildString( "StartupInfoA", "lpTitle" );
1286 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1287 "expected '%s' or null, got '%s'\n", selfname
, result
);
1288 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1289 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1290 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1291 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1292 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1293 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1294 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1295 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1296 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1298 assert(DeleteFileA(resfile
) != 0);
1301 static BOOL
is_console(HANDLE h
)
1303 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1306 static void test_Console(void)
1308 char buffer
[MAX_PATH
];
1309 PROCESS_INFORMATION info
;
1310 STARTUPINFOA startup
, us
;
1311 SECURITY_ATTRIBUTES sa
;
1312 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1313 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1314 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1316 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1317 const char* msg
= "This is a std-handle inheritance test.";
1319 BOOL run_tests
= TRUE
;
1322 memset(&startup
, 0, sizeof(startup
));
1323 startup
.cb
= sizeof(startup
);
1324 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1325 startup
.wShowWindow
= SW_SHOWNORMAL
;
1327 sa
.nLength
= sizeof(sa
);
1328 sa
.lpSecurityDescriptor
= NULL
;
1329 sa
.bInheritHandle
= TRUE
;
1331 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1332 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1334 /* first, we need to be sure we're attached to a console */
1335 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1337 /* we're not attached to a console, let's do it */
1339 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1340 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1342 /* now verify everything's ok */
1343 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1344 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1345 startup
.hStdError
= startup
.hStdOutput
;
1347 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1348 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
) &&
1349 GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console modes\n");
1350 cpIn
= GetConsoleCP();
1351 cpOut
= GetConsoleOutputCP();
1353 get_file_name(resfile
);
1354 sprintf(buffer
, "\"%s\" tests/process.c \"%s\" console", selfname
, resfile
);
1355 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1357 /* wait for child to terminate */
1358 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1359 /* child process has changed result file, so let profile functions know about it */
1360 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1362 /* now get the modification the child has made, and resets parents expected values */
1363 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1364 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
) &&
1365 GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console modes\n");
1367 SetConsoleMode(startup
.hStdInput
, modeIn
);
1368 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1370 cpInC
= GetConsoleCP();
1371 cpOutC
= GetConsoleOutputCP();
1373 /* Try to set invalid CP */
1374 SetLastError(0xdeadbeef);
1375 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1376 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1377 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1378 "GetLastError: expecting %u got %u\n",
1379 ERROR_INVALID_PARAMETER
, GetLastError());
1380 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1384 SetLastError(0xdeadbeef);
1385 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1386 ok(GetLastError()==ERROR_INVALID_PARAMETER
||
1387 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
), /* win9x */
1388 "GetLastError: expecting %u got %u\n",
1389 ERROR_INVALID_PARAMETER
, GetLastError());
1392 SetConsoleOutputCP(cpOut
);
1394 GetStartupInfoA(&us
);
1396 okChildInt("StartupInfoA", "cb", startup
.cb
);
1397 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1398 result
= getChildString( "StartupInfoA", "lpTitle" );
1399 ok( broken(!result
) || (result
&& !strCmp( result
, selfname
, 0 )),
1400 "expected '%s' or null, got '%s'\n", selfname
, result
);
1401 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1402 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1403 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1404 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1405 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1406 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1407 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1408 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1409 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1411 /* check child correctly inherited the console */
1412 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR
)startup
.hStdInput
);
1413 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR
)startup
.hStdOutput
);
1414 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR
)startup
.hStdError
);
1415 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1416 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1417 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1418 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1419 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1420 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1421 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1422 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1423 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1424 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1425 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1426 okChildInt("Console", "InputCP", cpIn
);
1427 okChildInt("Console", "OutputCP", cpOut
);
1428 okChildInt("Console", "InputMode", modeIn
);
1429 okChildInt("Console", "OutputMode", modeOut
);
1433 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1434 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1437 win_skip("Setting the codepage is not implemented\n");
1439 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1440 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1441 trace("cursor position(X): %d/%d\n",sbi
.dwCursorPosition
.X
, sbiC
.dwCursorPosition
.X
);
1442 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1445 assert(DeleteFileA(resfile
) != 0);
1447 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1448 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1449 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1450 "Duplicating as inheritable child-output pipe\n");
1451 CloseHandle(hChildOut
);
1453 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1454 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1455 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1456 "Duplicating as inheritable child-input pipe\n");
1457 CloseHandle(hChildIn
);
1459 memset(&startup
, 0, sizeof(startup
));
1460 startup
.cb
= sizeof(startup
);
1461 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1462 startup
.wShowWindow
= SW_SHOWNORMAL
;
1463 startup
.hStdInput
= hChildInInh
;
1464 startup
.hStdOutput
= hChildOutInh
;
1465 startup
.hStdError
= hChildOutInh
;
1467 get_file_name(resfile
);
1468 sprintf(buffer
, "\"%s\" tests/process.c \"%s\" stdhandle", selfname
, resfile
);
1469 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1470 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1471 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1473 msg_len
= strlen(msg
) + 1;
1474 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1475 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1476 memset(buffer
, 0, sizeof(buffer
));
1477 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1478 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1480 /* wait for child to terminate */
1481 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1482 /* child process has changed result file, so let profile functions know about it */
1483 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1485 okChildString("StdHandle", "msg", msg
);
1488 assert(DeleteFileA(resfile
) != 0);
1491 static void test_ExitCode(void)
1493 char buffer
[MAX_PATH
];
1494 PROCESS_INFORMATION info
;
1495 STARTUPINFOA startup
;
1498 /* let's start simplistic */
1499 memset(&startup
, 0, sizeof(startup
));
1500 startup
.cb
= sizeof(startup
);
1501 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1502 startup
.wShowWindow
= SW_SHOWNORMAL
;
1504 get_file_name(resfile
);
1505 sprintf(buffer
, "\"%s\" tests/process.c \"%s\" exit_code", selfname
, resfile
);
1506 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1508 /* wait for child to terminate */
1509 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1510 /* child process has changed result file, so let profile functions know about it */
1511 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1513 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1514 okChildInt("ExitCode", "value", code
);
1517 assert(DeleteFileA(resfile
) != 0);
1520 static void test_OpenProcess(void)
1524 MEMORY_BASIC_INFORMATION info
;
1525 SIZE_T dummy
, read_bytes
;
1528 /* not exported in all windows versions */
1529 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1530 win_skip("VirtualAllocEx not found\n");
1534 /* without PROCESS_VM_OPERATION */
1535 hproc
= OpenProcess(PROCESS_ALL_ACCESS
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1536 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1538 SetLastError(0xdeadbeef);
1539 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1540 ok(!addr1
, "VirtualAllocEx should fail\n");
1541 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1544 win_skip("VirtualAllocEx not implemented\n");
1547 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1549 read_bytes
= 0xdeadbeef;
1550 SetLastError(0xdeadbeef);
1551 ret
= ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
);
1552 ok(ret
, "ReadProcessMemory error %d\n", GetLastError());
1553 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1557 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1558 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1560 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1561 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1563 /* without PROCESS_QUERY_INFORMATION */
1564 SetLastError(0xdeadbeef);
1565 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1566 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1567 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1569 /* without PROCESS_VM_READ */
1570 read_bytes
= 0xdeadbeef;
1571 SetLastError(0xdeadbeef);
1572 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1573 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1574 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1575 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1579 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1581 memset(&info
, 0xcc, sizeof(info
));
1582 read_bytes
= VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
));
1583 ok(read_bytes
== sizeof(info
), "VirtualQueryEx error %d\n", GetLastError());
1585 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1586 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1587 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1588 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1589 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1590 /* NT reports Protect == 0 for a not committed memory block */
1591 ok(info
.Protect
== 0 /* NT */ ||
1592 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1593 "%x != PAGE_NOACCESS\n", info
.Protect
);
1594 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1596 SetLastError(0xdeadbeef);
1597 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1598 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1599 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1603 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1606 static void test_GetProcessVersion(void)
1608 static char cmdline
[] = "winver.exe";
1609 PROCESS_INFORMATION pi
;
1613 SetLastError(0xdeadbeef);
1614 ret
= GetProcessVersion(0);
1615 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1617 SetLastError(0xdeadbeef);
1618 ret
= GetProcessVersion(GetCurrentProcessId());
1619 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1621 memset(&si
, 0, sizeof(si
));
1623 si
.dwFlags
= STARTF_USESHOWWINDOW
;
1624 si
.wShowWindow
= SW_HIDE
;
1625 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1626 SetLastError(0xdeadbeef);
1627 ok(ret
, "CreateProcess error %u\n", GetLastError());
1629 SetLastError(0xdeadbeef);
1630 ret
= GetProcessVersion(pi
.dwProcessId
);
1631 ok(ret
, "GetProcessVersion error %u\n", GetLastError());
1633 SetLastError(0xdeadbeef);
1634 ret
= TerminateProcess(pi
.hProcess
, 0);
1635 ok(ret
, "TerminateProcess error %u\n", GetLastError());
1637 CloseHandle(pi
.hProcess
);
1638 CloseHandle(pi
.hThread
);
1641 static void test_ProcessNameA(void)
1643 #define INIT_STR "Just some words"
1647 if (!pQueryFullProcessImageNameA
)
1649 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1652 /* get the buffer length without \0 terminator */
1654 expect_eq_d(TRUE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &length
));
1655 expect_eq_d(length
, lstrlenA(buf
));
1657 /* when the buffer is too small
1658 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1659 * - the size variable is not modified
1660 * tested with the biggest too small size
1663 sprintf(buf
,INIT_STR
);
1664 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1665 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1666 expect_eq_d(length
, size
);
1667 expect_eq_s(INIT_STR
, buf
);
1669 /* retest with smaller buffer size
1672 sprintf(buf
,INIT_STR
);
1673 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf
, &size
));
1674 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1675 expect_eq_d(4, size
);
1676 expect_eq_s(INIT_STR
, buf
);
1678 /* this is a difference between the ascii and the unicode version
1679 * the unicode version crashes when the size is big enough to hold the result
1680 * ascii version through an error
1683 expect_eq_d(FALSE
, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL
, &size
));
1684 expect_eq_d(1024, size
);
1685 expect_eq_d(ERROR_INVALID_PARAMETER
, GetLastError());
1688 static void test_ProcessName(void)
1691 WCHAR module_name
[1024];
1692 WCHAR deviceW
[] = {'\\','D', 'e','v','i','c','e',0};
1696 if (!pQueryFullProcessImageNameW
)
1698 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1702 ok(GetModuleFileNameW(NULL
, module_name
, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1704 /* GetCurrentProcess pseudo-handle */
1705 size
= sizeof(buf
) / sizeof(buf
[0]);
1706 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf
, &size
));
1707 expect_eq_d(lstrlenW(buf
), size
);
1708 expect_eq_ws_i(buf
, module_name
);
1710 hSelf
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1712 size
= sizeof(buf
) / sizeof(buf
[0]);
1713 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1714 expect_eq_d(lstrlenW(buf
), size
);
1715 expect_eq_ws_i(buf
, module_name
);
1717 /* Buffer too small */
1718 size
= lstrlenW(module_name
)/2;
1719 lstrcpyW(buf
, deviceW
);
1720 SetLastError(0xdeadbeef);
1721 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1722 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1723 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1724 expect_eq_ws_i(deviceW
, buf
); /* buffer not changed */
1726 /* Too small - not space for NUL terminator */
1727 size
= lstrlenW(module_name
);
1728 SetLastError(0xdeadbeef);
1729 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1730 expect_eq_d(lstrlenW(module_name
), size
); /* size not changed(!) */
1731 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1735 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, NULL
, &size
));
1736 expect_eq_d(0, size
);
1737 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1740 size
= sizeof(buf
) / sizeof(buf
[0]);
1741 expect_eq_d(TRUE
, pQueryFullProcessImageNameW(hSelf
, PROCESS_NAME_NATIVE
, buf
, &size
));
1742 expect_eq_d(lstrlenW(buf
), size
);
1743 ok(buf
[0] == '\\', "NT path should begin with '\\'\n");
1744 todo_wine
ok(memcmp(buf
, deviceW
, sizeof(WCHAR
)*lstrlenW(deviceW
)) == 0, "NT path should begin with \\Device\n");
1746 /* Buffer too small */
1747 size
= lstrlenW(module_name
)/2;
1748 SetLastError(0xdeadbeef);
1749 lstrcpyW(buf
, module_name
);
1750 expect_eq_d(FALSE
, pQueryFullProcessImageNameW(hSelf
, 0, buf
, &size
));
1751 expect_eq_d(lstrlenW(module_name
)/2, size
); /* size not changed(!) */
1752 expect_eq_d(ERROR_INSUFFICIENT_BUFFER
, GetLastError());
1753 expect_eq_ws_i(module_name
, buf
); /* buffer not changed */
1758 static void test_Handles(void)
1760 HANDLE handle
= GetCurrentProcess();
1765 ok( handle
== (HANDLE
)~(ULONG_PTR
)0 ||
1766 handle
== (HANDLE
)(ULONG_PTR
)0x7fffffff /* win9x */,
1767 "invalid current process handle %p\n", handle
);
1768 ret
= GetExitCodeProcess( handle
, &code
);
1769 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1771 /* truncated handle */
1772 SetLastError( 0xdeadbeef );
1773 handle
= (HANDLE
)((ULONG_PTR
)handle
& ~0u);
1774 ret
= GetExitCodeProcess( handle
, &code
);
1775 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1776 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1777 /* sign-extended handle */
1778 SetLastError( 0xdeadbeef );
1779 handle
= (HANDLE
)((LONG_PTR
)(int)(ULONG_PTR
)handle
);
1780 ret
= GetExitCodeProcess( handle
, &code
);
1781 ok( ret
, "GetExitCodeProcess failed err %u\n", GetLastError() );
1782 /* invalid high-word */
1783 SetLastError( 0xdeadbeef );
1784 handle
= (HANDLE
)(((ULONG_PTR
)handle
& ~0u) + ((ULONG_PTR
)1 << 32));
1785 ret
= GetExitCodeProcess( handle
, &code
);
1786 ok( !ret
, "GetExitCodeProcess succeeded for %p\n", handle
);
1787 ok( GetLastError() == ERROR_INVALID_HANDLE
, "wrong error %u\n", GetLastError() );
1790 handle
= GetStdHandle( STD_ERROR_HANDLE
);
1791 ok( handle
!= 0, "handle %p\n", handle
);
1792 DuplicateHandle( GetCurrentProcess(), handle
, GetCurrentProcess(), &h3
,
1793 0, TRUE
, DUPLICATE_SAME_ACCESS
);
1794 SetStdHandle( STD_ERROR_HANDLE
, h3
);
1795 CloseHandle( (HANDLE
)STD_ERROR_HANDLE
);
1796 h2
= GetStdHandle( STD_ERROR_HANDLE
);
1798 broken( h2
== h3
) || /* nt4, w2k */
1799 broken( h2
== INVALID_HANDLE_VALUE
), /* win9x */
1800 "wrong handle %p/%p\n", h2
, h3
);
1801 SetStdHandle( STD_ERROR_HANDLE
, handle
);
1804 static void test_SystemInfo(void)
1806 SYSTEM_INFO si
, nsi
;
1809 if (!pGetNativeSystemInfo
)
1811 win_skip("GetNativeSystemInfo is not available\n");
1815 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
1818 pGetNativeSystemInfo(&nsi
);
1821 if (S(U(si
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
1823 ok(S(U(nsi
)).wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
,
1824 "Expected PROCESSOR_ARCHITECTURE_AMD64, got %d\n",
1825 S(U(nsi
)).wProcessorArchitecture
);
1826 ok(nsi
.dwProcessorType
== PROCESSOR_AMD_X8664
,
1827 "Expected PROCESSOR_AMD_X8664, got %d\n",
1828 nsi
.dwProcessorType
);
1833 ok(S(U(si
)).wProcessorArchitecture
== S(U(nsi
)).wProcessorArchitecture
,
1834 "Expected no difference for wProcessorArchitecture, got %d and %d\n",
1835 S(U(si
)).wProcessorArchitecture
, S(U(nsi
)).wProcessorArchitecture
);
1836 ok(si
.dwProcessorType
== nsi
.dwProcessorType
,
1837 "Expected no difference for dwProcessorType, got %d and %d\n",
1838 si
.dwProcessorType
, nsi
.dwProcessorType
);
1842 static void test_RegistryQuota(void)
1845 DWORD max_quota
, used_quota
;
1847 if (!pGetSystemRegistryQuota
)
1849 win_skip("GetSystemRegistryQuota is not available\n");
1853 ret
= pGetSystemRegistryQuota(NULL
, NULL
);
1855 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
1857 ret
= pGetSystemRegistryQuota(&max_quota
, NULL
);
1859 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
1861 ret
= pGetSystemRegistryQuota(NULL
, &used_quota
);
1863 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
1865 ret
= pGetSystemRegistryQuota(&max_quota
, &used_quota
);
1867 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret
);
1873 ok(b
, "Basic init of CreateProcess test\n");
1878 doChild(myARGV
[2], (myARGC
== 3) ? NULL
: myARGV
[3]);
1886 test_DebuggingFlag();
1890 test_GetProcessVersion();
1891 test_ProcessNameA();
1895 test_RegistryQuota();
1896 /* things that can be tested:
1897 * lookup: check the way program to be executed is searched
1898 * handles: check the handle inheritance stuff (+sec options)
1899 * console: check if console creation parameters work