sync kernel32_winetest with wine 1.1.28
[reactos.git] / rostests / winetests / kernel32 / process.c
1 /*
2 * Unit test suite for CreateProcess function.
3 *
4 * Copyright 2002 Eric Pouech
5 * Copyright 2006 Dmitry Timoshkov
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "wincon.h"
33 #include "winnls.h"
34 #include "winternl.h"
35
36 #include "wine/test.h"
37
38 #define PROCESS_NAME_NATIVE 1
39
40 #define expect_eq_d(expected, actual) \
41 do { \
42 int value = (actual); \
43 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
44 (expected), value); \
45 } while (0)
46 #define expect_eq_s(expected, actual) \
47 do { \
48 LPCSTR value = (actual); \
49 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
50 expected, value); \
51 } while (0)
52 #define expect_eq_ws_i(expected, actual) \
53 do { \
54 LPCWSTR value = (actual); \
55 ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
56 wine_dbgstr_w(expected), wine_dbgstr_w(value)); \
57 } while (0)
58
59 static HINSTANCE hkernel32;
60 static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
61 static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
62 static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize);
63 static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize);
64
65 /* ############################### */
66 static char base[MAX_PATH];
67 static char selfname[MAX_PATH];
68 static char* exename;
69 static char resfile[MAX_PATH];
70
71 static int myARGC;
72 static char** myARGV;
73
74 /* As some environment variables get very long on Unix, we only test for
75 * the first 127 bytes.
76 * Note that increasing this value past 256 may exceed the buffer size
77 * limitations of the *Profile functions (at least on Wine).
78 */
79 #define MAX_LISTED_ENV_VAR 128
80
81 /* ---------------- portable memory allocation thingie */
82
83 static char memory[1024*256];
84 static char* memory_index = memory;
85
86 static char* grab_memory(size_t len)
87 {
88 char* ret = memory_index;
89 /* align on dword */
90 len = (len + 3) & ~3;
91 memory_index += len;
92 assert(memory_index <= memory + sizeof(memory));
93 return ret;
94 }
95
96 static void release_memory(void)
97 {
98 memory_index = memory;
99 }
100
101 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
102
103 static const char* encodeA(const char* str)
104 {
105 char* ptr;
106 size_t len,i;
107
108 if (!str) return "";
109 len = strlen(str) + 1;
110 ptr = grab_memory(len * 2 + 1);
111 for (i = 0; i < len; i++)
112 sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
113 ptr[2 * len] = '\0';
114 return ptr;
115 }
116
117 static const char* encodeW(const WCHAR* str)
118 {
119 char* ptr;
120 size_t len,i;
121
122 if (!str) return "";
123 len = lstrlenW(str) + 1;
124 ptr = grab_memory(len * 4 + 1);
125 assert(ptr);
126 for (i = 0; i < len; i++)
127 sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
128 ptr[4 * len] = '\0';
129 return ptr;
130 }
131
132 static unsigned decode_char(char c)
133 {
134 if (c >= '0' && c <= '9') return c - '0';
135 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
136 assert(c >= 'A' && c <= 'F');
137 return c - 'A' + 10;
138 }
139
140 static char* decodeA(const char* str)
141 {
142 char* ptr;
143 size_t len,i;
144
145 len = strlen(str) / 2;
146 if (!len--) return NULL;
147 ptr = grab_memory(len + 1);
148 for (i = 0; i < len; i++)
149 ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
150 ptr[len] = '\0';
151 return ptr;
152 }
153
154 /* This will be needed to decode Unicode strings saved by the child process
155 * when we test Unicode functions.
156 */
157 static WCHAR* decodeW(const char* str)
158 {
159 size_t len;
160 WCHAR* ptr;
161 int i;
162
163 len = strlen(str) / 4;
164 if (!len--) return NULL;
165 ptr = (WCHAR*)grab_memory(len * 2 + 1);
166 for (i = 0; i < len; i++)
167 ptr[i] = (decode_char(str[4 * i]) << 12) |
168 (decode_char(str[4 * i + 1]) << 8) |
169 (decode_char(str[4 * i + 2]) << 4) |
170 (decode_char(str[4 * i + 3]) << 0);
171 ptr[len] = '\0';
172 return ptr;
173 }
174
175 /******************************************************************
176 * init
177 *
178 * generates basic information like:
179 * base: absolute path to curr dir
180 * selfname: the way to reinvoke ourselves
181 * exename: executable without the path
182 * function-pointers, which are not implemented in all windows versions
183 */
184 static int init(void)
185 {
186 char *p;
187
188 myARGC = winetest_get_mainargs( &myARGV );
189 if (!GetCurrentDirectoryA(sizeof(base), base)) return 0;
190 strcpy(selfname, myARGV[0]);
191
192 /* Strip the path of selfname */
193 if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1;
194 else exename = selfname;
195
196 if ((p = strrchr(exename, '/')) != NULL) exename = p + 1;
197
198 hkernel32 = GetModuleHandleA("kernel32");
199 pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
200 pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
201 pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA");
202 pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW");
203 return 1;
204 }
205
206 /******************************************************************
207 * get_file_name
208 *
209 * generates an absolute file_name for temporary file
210 *
211 */
212 static void get_file_name(char* buf)
213 {
214 char path[MAX_PATH];
215
216 buf[0] = '\0';
217 GetTempPathA(sizeof(path), path);
218 GetTempFileNameA(path, "wt", 0, buf);
219 }
220
221 /******************************************************************
222 * static void childPrintf
223 *
224 */
225 static void childPrintf(HANDLE h, const char* fmt, ...)
226 {
227 va_list valist;
228 char buffer[1024+4*MAX_LISTED_ENV_VAR];
229 DWORD w;
230
231 va_start(valist, fmt);
232 vsprintf(buffer, fmt, valist);
233 va_end(valist);
234 WriteFile(h, buffer, strlen(buffer), &w, NULL);
235 }
236
237
238 /******************************************************************
239 * doChild
240 *
241 * output most of the information in the child process
242 */
243 static void doChild(const char* file, const char* option)
244 {
245 STARTUPINFOA siA;
246 STARTUPINFOW siW;
247 int i;
248 char* ptrA;
249 WCHAR* ptrW;
250 char bufA[MAX_PATH];
251 WCHAR bufW[MAX_PATH];
252 HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
253 BOOL ret;
254
255 if (hFile == INVALID_HANDLE_VALUE) return;
256
257 /* output of startup info (Ansi) */
258 GetStartupInfoA(&siA);
259 childPrintf(hFile,
260 "[StartupInfoA]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
261 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
262 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
263 "dwFlags=%lu\nwShowWindow=%u\n"
264 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
265 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
266 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize,
267 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute,
268 siA.dwFlags, siA.wShowWindow,
269 (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError);
270
271 /* since GetStartupInfoW is only implemented in win2k,
272 * zero out before calling so we can notice the difference
273 */
274 memset(&siW, 0, sizeof(siW));
275 GetStartupInfoW(&siW);
276 childPrintf(hFile,
277 "[StartupInfoW]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
278 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
279 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
280 "dwFlags=%lu\nwShowWindow=%u\n"
281 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
282 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
283 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize,
284 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute,
285 siW.dwFlags, siW.wShowWindow,
286 (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError);
287
288 /* Arguments */
289 childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
290 for (i = 0; i < myARGC; i++)
291 {
292 childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
293 }
294 childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
295
296 #if 0
297 int argcW;
298 WCHAR** argvW;
299
300 /* this is part of shell32... and should be tested there */
301 argvW = CommandLineToArgvW(GetCommandLineW(), &argcW);
302 for (i = 0; i < argcW; i++)
303 {
304 childPrintf(hFile, "argvW%d=%s\n", i, encodeW(argvW[i]));
305 }
306 #endif
307 childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
308
309 /* output of environment (Ansi) */
310 ptrA = GetEnvironmentStringsA();
311 if (ptrA)
312 {
313 char env_var[MAX_LISTED_ENV_VAR];
314
315 childPrintf(hFile, "[EnvironmentA]\n");
316 i = 0;
317 while (*ptrA)
318 {
319 lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR);
320 childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
321 i++;
322 ptrA += strlen(ptrA) + 1;
323 }
324 childPrintf(hFile, "len=%d\n\n", i);
325 }
326
327 /* output of environment (Unicode) */
328 ptrW = GetEnvironmentStringsW();
329 if (ptrW)
330 {
331 WCHAR env_var[MAX_LISTED_ENV_VAR];
332
333 childPrintf(hFile, "[EnvironmentW]\n");
334 i = 0;
335 while (*ptrW)
336 {
337 lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1);
338 env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
339 childPrintf(hFile, "env%d=%s\n", i, encodeW(env_var));
340 i++;
341 ptrW += lstrlenW(ptrW) + 1;
342 }
343 childPrintf(hFile, "len=%d\n\n", i);
344 }
345
346 childPrintf(hFile, "[Misc]\n");
347 if (GetCurrentDirectoryA(sizeof(bufA), bufA))
348 childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
349 if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW))
350 childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
351 childPrintf(hFile, "\n");
352
353 if (option && strcmp(option, "console") == 0)
354 {
355 CONSOLE_SCREEN_BUFFER_INFO sbi;
356 HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE);
357 HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
358 DWORD modeIn, modeOut;
359
360 childPrintf(hFile, "[Console]\n");
361 if (GetConsoleScreenBufferInfo(hConOut, &sbi))
362 {
363 childPrintf(hFile, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
364 sbi.dwSize.X, sbi.dwSize.Y, sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y, sbi.wAttributes);
365 childPrintf(hFile, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
366 sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom);
367 childPrintf(hFile, "maxWinWidth=%d\nmaxWinHeight=%d\n",
368 sbi.dwMaximumWindowSize.X, sbi.dwMaximumWindowSize.Y);
369 }
370 childPrintf(hFile, "InputCP=%d\nOutputCP=%d\n",
371 GetConsoleCP(), GetConsoleOutputCP());
372 if (GetConsoleMode(hConIn, &modeIn))
373 childPrintf(hFile, "InputMode=%ld\n", modeIn);
374 if (GetConsoleMode(hConOut, &modeOut))
375 childPrintf(hFile, "OutputMode=%ld\n", modeOut);
376
377 /* now that we have written all relevant information, let's change it */
378 SetLastError(0xdeadbeef);
379 ret = SetConsoleCP(1252);
380 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
381 {
382 win_skip("Setting the codepage is not implemented\n");
383 }
384 else
385 {
386 ok(ret, "Setting CP\n");
387 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
388 }
389
390 ret = SetConsoleMode(hConIn, modeIn ^ 1);
391 ok( ret, "Setting mode (%d)\n", GetLastError());
392 ret = SetConsoleMode(hConOut, modeOut ^ 1);
393 ok( ret, "Setting mode (%d)\n", GetLastError());
394 sbi.dwCursorPosition.X ^= 1;
395 sbi.dwCursorPosition.Y ^= 1;
396 ret = SetConsoleCursorPosition(hConOut, sbi.dwCursorPosition);
397 ok( ret, "Setting cursor position (%d)\n", GetLastError());
398 }
399 if (option && strcmp(option, "stdhandle") == 0)
400 {
401 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
402 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
403
404 if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE)
405 {
406 char buf[1024];
407 DWORD r, w;
408
409 ok(ReadFile(hStdIn, buf, sizeof(buf), &r, NULL) && r > 0, "Reading message from input pipe\n");
410 childPrintf(hFile, "[StdHandle]\nmsg=%s\n\n", encodeA(buf));
411 ok(WriteFile(hStdOut, buf, r, &w, NULL) && w == r, "Writing message to output pipe\n");
412 }
413 }
414
415 if (option && strcmp(option, "exit_code") == 0)
416 {
417 childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123);
418 CloseHandle(hFile);
419 ExitProcess(123);
420 }
421
422 CloseHandle(hFile);
423 }
424
425 static char* getChildString(const char* sect, const char* key)
426 {
427 char buf[1024+4*MAX_LISTED_ENV_VAR];
428 char* ret;
429
430 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
431 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
432 assert(!(strlen(buf) & 1));
433 ret = decodeA(buf);
434 return ret;
435 }
436
437 static WCHAR* getChildStringW(const char* sect, const char* key)
438 {
439 char buf[1024+4*MAX_LISTED_ENV_VAR];
440 WCHAR* ret;
441
442 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
443 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
444 assert(!(strlen(buf) & 1));
445 ret = decodeW(buf);
446 return ret;
447 }
448
449 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
450 * others... (windows uses stricmp while Un*x uses strcasecmp...)
451 */
452 static int wtstrcasecmp(const char* p1, const char* p2)
453 {
454 char c1, c2;
455
456 c1 = c2 = '@';
457 while (c1 == c2 && c1)
458 {
459 c1 = *p1++; c2 = *p2++;
460 if (c1 != c2)
461 {
462 c1 = toupper(c1); c2 = toupper(c2);
463 }
464 }
465 return c1 - c2;
466 }
467
468 static int strCmp(const char* s1, const char* s2, BOOL sensitive)
469 {
470 if (!s1 && !s2) return 0;
471 if (!s2) return -1;
472 if (!s1) return 1;
473 return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2);
474 }
475
476 static void ok_child_string( int line, const char *sect, const char *key,
477 const char *expect, int sensitive )
478 {
479 char* result = getChildString( sect, key );
480 ok_(__FILE__, line)( strCmp(result, expect, sensitive) == 0, "%s:%s expected '%s', got '%s'\n",
481 sect, key, expect ? expect : "(null)", result );
482 }
483
484 static void ok_child_stringWA( int line, const char *sect, const char *key,
485 const char *expect, int sensitive )
486 {
487 WCHAR* expectW;
488 CHAR* resultA;
489 DWORD len;
490 WCHAR* result = getChildStringW( sect, key );
491
492 len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0);
493 expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
494 MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len);
495
496 len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL);
497 resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR));
498 WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL);
499
500 if (sensitive)
501 ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
502 sect, key, expect ? expect : "(null)", resultA );
503 else
504 ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
505 sect, key, expect ? expect : "(null)", resultA );
506 HeapFree(GetProcessHeap(),0,expectW);
507 HeapFree(GetProcessHeap(),0,resultA);
508 }
509
510 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
511 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
512 #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 )
513
514 /* using !expect ensures that the test will fail if the sect/key isn't present
515 * in result file
516 */
517 #define okChildInt(sect, key, expect) \
518 do { \
519 UINT result = GetPrivateProfileIntA((sect), (key), !(expect), resfile); \
520 ok(result == expect, "%s:%s expected %u, but got %u\n", (sect), (key), (UINT)(expect), result); \
521 } while (0)
522
523 static void test_Startup(void)
524 {
525 char buffer[MAX_PATH];
526 PROCESS_INFORMATION info;
527 STARTUPINFOA startup,si;
528 static CHAR title[] = "I'm the title string",
529 desktop[] = "winsta0\\default",
530 empty[] = "";
531
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;
537
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);
545
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);
558 release_memory();
559 assert(DeleteFileA(resfile) != 0);
560
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;
575
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);
583
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);
596 release_memory();
597 assert(DeleteFileA(resfile) != 0);
598
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;
613
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);
621
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);
634 release_memory();
635 assert(DeleteFileA(resfile) != 0);
636
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;
651
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);
659
660 okChildInt("StartupInfoA", "cb", startup.cb);
661 todo_wine 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);
672 release_memory();
673 assert(DeleteFileA(resfile) != 0);
674
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;
689
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);
697
698 okChildInt("StartupInfoA", "cb", startup.cb);
699 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
700 ok (startup.lpTitle == NULL || !strcmp(startup.lpTitle, selfname),
701 "StartupInfoA:lpTitle expected '%s' or null, got '%s'\n", selfname, startup.lpTitle);
702 okChildInt("StartupInfoA", "dwX", startup.dwX);
703 okChildInt("StartupInfoA", "dwY", startup.dwY);
704 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
705 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
706 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
707 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
708 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
709 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
710 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
711 release_memory();
712 assert(DeleteFileA(resfile) != 0);
713
714 /* not so simplistic now */
715 memset(&startup, 0, sizeof(startup));
716 startup.cb = sizeof(startup);
717 startup.dwFlags = STARTF_USESHOWWINDOW;
718 startup.wShowWindow = SW_SHOWNORMAL;
719 startup.lpTitle = empty;
720 startup.lpDesktop = desktop;
721 startup.dwXCountChars = 0x12121212;
722 startup.dwYCountChars = 0x23232323;
723 startup.dwX = 0x34343434;
724 startup.dwY = 0x45454545;
725 startup.dwXSize = 0x56565656;
726 startup.dwYSize = 0x67676767;
727 startup.dwFillAttribute = 0xA55A;
728
729 get_file_name(resfile);
730 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
731 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
732 /* wait for child to terminate */
733 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
734 /* child process has changed result file, so let profile functions know about it */
735 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
736
737 okChildInt("StartupInfoA", "cb", startup.cb);
738 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
739 todo_wine okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
740 okChildInt("StartupInfoA", "dwX", startup.dwX);
741 okChildInt("StartupInfoA", "dwY", startup.dwY);
742 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
743 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
744 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
745 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
746 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
747 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
748 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
749 release_memory();
750 assert(DeleteFileA(resfile) != 0);
751
752 /* not so simplistic now */
753 memset(&startup, 0, sizeof(startup));
754 startup.cb = sizeof(startup);
755 startup.dwFlags = STARTF_USESHOWWINDOW;
756 startup.wShowWindow = SW_SHOWNORMAL;
757 startup.lpTitle = empty;
758 startup.lpDesktop = empty;
759 startup.dwXCountChars = 0x12121212;
760 startup.dwYCountChars = 0x23232323;
761 startup.dwX = 0x34343434;
762 startup.dwY = 0x45454545;
763 startup.dwXSize = 0x56565656;
764 startup.dwYSize = 0x67676767;
765 startup.dwFillAttribute = 0xA55A;
766
767 get_file_name(resfile);
768 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
769 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
770 /* wait for child to terminate */
771 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
772 /* child process has changed result file, so let profile functions know about it */
773 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
774
775 okChildInt("StartupInfoA", "cb", startup.cb);
776 todo_wine okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
777 todo_wine okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
778 okChildInt("StartupInfoA", "dwX", startup.dwX);
779 okChildInt("StartupInfoA", "dwY", startup.dwY);
780 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
781 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
782 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
783 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
784 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
785 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
786 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
787 release_memory();
788 assert(DeleteFileA(resfile) != 0);
789
790 /* TODO: test for A/W and W/A and W/W */
791 }
792
793 static void test_CommandLine(void)
794 {
795 char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
796 char buffer2[MAX_PATH];
797 PROCESS_INFORMATION info;
798 STARTUPINFOA startup;
799 DWORD len;
800 BOOL ret;
801
802 memset(&startup, 0, sizeof(startup));
803 startup.cb = sizeof(startup);
804 startup.dwFlags = STARTF_USESHOWWINDOW;
805 startup.wShowWindow = SW_SHOWNORMAL;
806
807 /* the basics */
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);
815
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);
820 release_memory();
821 assert(DeleteFileA(resfile) != 0);
822
823 memset(&startup, 0, sizeof(startup));
824 startup.cb = sizeof(startup);
825 startup.dwFlags = STARTF_USESHOWWINDOW;
826 startup.wShowWindow = SW_SHOWNORMAL;
827
828 /* from Frangois */
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);
836
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);
843 release_memory();
844 assert(DeleteFileA(resfile) != 0);
845
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);
859 release_memory();
860 assert(DeleteFileA(resfile) != 0);
861
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);
874 release_memory();
875 assert(DeleteFileA(resfile) != 0);
876
877 get_file_name(resfile);
878 len = 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);
895 release_memory();
896 assert(DeleteFileA(resfile) != 0);
897
898 /* Using AppName */
899 get_file_name(resfile);
900 len = 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);
919 release_memory();
920 assert(DeleteFileA(resfile) != 0);
921
922 if (0) /* Test crashes on NT-based Windows. */
923 {
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());
930 }
931
932 buffer[0] = '\0';
933
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());
942
943 buffer2[0] = '\0';
944
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());
953
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 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
962
963 strcpy(buffer, "doesnotexist.exe");
964 strcpy(buffer2, "does not exist.exe");
965
966 /* Test nonexistent application name. */
967 SetLastError(0xdeadbeef);
968 ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
969 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
970 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
971
972 SetLastError(0xdeadbeef);
973 ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
974 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
975 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
976
977 /* Test nonexistent command line parameter. */
978 SetLastError(0xdeadbeef);
979 ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
980 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
981 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
982
983 SetLastError(0xdeadbeef);
984 ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
985 ok(!ret, "CreateProcessA unexpectedly succeeded\n");
986 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
987 }
988
989 static void test_Directory(void)
990 {
991 char buffer[MAX_PATH];
992 PROCESS_INFORMATION info;
993 STARTUPINFOA startup;
994 char windir[MAX_PATH];
995 static CHAR cmdline[] = "winver.exe";
996
997 memset(&startup, 0, sizeof(startup));
998 startup.cb = sizeof(startup);
999 startup.dwFlags = STARTF_USESHOWWINDOW;
1000 startup.wShowWindow = SW_SHOWNORMAL;
1001
1002 /* the basics */
1003 get_file_name(resfile);
1004 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
1005 GetWindowsDirectoryA( windir, sizeof(windir) );
1006 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess\n");
1007 /* wait for child to terminate */
1008 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1009 /* child process has changed result file, so let profile functions know about it */
1010 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1011
1012 okChildIString("Misc", "CurrDirA", windir);
1013 release_memory();
1014 assert(DeleteFileA(resfile) != 0);
1015
1016 /* search PATH for the exe if directory is NULL */
1017 ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1018 ok(TerminateProcess(info.hProcess, 0), "Child process termination\n");
1019
1020 /* if any directory is provided, don't search PATH, error on bad directory */
1021 SetLastError(0xdeadbeef);
1022 memset(&info, 0, sizeof(info));
1023 ok(!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L,
1024 NULL, "non\\existent\\directory", &startup, &info), "CreateProcess\n");
1025 ok(GetLastError() == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
1026 ok(!TerminateProcess(info.hProcess, 0), "Child process should not exist\n");
1027 }
1028
1029 static BOOL is_str_env_drive_dir(const char* str)
1030 {
1031 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1032 str[3] == '=' && str[4] == str[1];
1033 }
1034
1035 /* compared expected child's environment (in gesA) from actual
1036 * environment our child got
1037 */
1038 static void cmpEnvironment(const char* gesA)
1039 {
1040 int i, clen;
1041 const char* ptrA;
1042 char* res;
1043 char key[32];
1044 BOOL found;
1045
1046 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1047
1048 /* now look each parent env in child */
1049 if ((ptrA = gesA) != NULL)
1050 {
1051 while (*ptrA)
1052 {
1053 for (i = 0; i < clen; i++)
1054 {
1055 sprintf(key, "env%d", i);
1056 res = getChildString("EnvironmentA", key);
1057 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1058 break;
1059 }
1060 found = i < clen;
1061 ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1062
1063 ptrA += strlen(ptrA) + 1;
1064 release_memory();
1065 }
1066 }
1067 /* and each child env in parent */
1068 for (i = 0; i < clen; i++)
1069 {
1070 sprintf(key, "env%d", i);
1071 res = getChildString("EnvironmentA", key);
1072 if ((ptrA = gesA) != NULL)
1073 {
1074 while (*ptrA)
1075 {
1076 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1077 break;
1078 ptrA += strlen(ptrA) + 1;
1079 }
1080 if (!*ptrA) ptrA = NULL;
1081 }
1082
1083 if (!is_str_env_drive_dir(res))
1084 {
1085 found = ptrA != NULL;
1086 ok(found, "Child-env string %s isn't in parent process\n", res);
1087 }
1088 /* else => should also test we get the right per drive default directory here... */
1089 }
1090 }
1091
1092 static void test_Environment(void)
1093 {
1094 char buffer[MAX_PATH];
1095 PROCESS_INFORMATION info;
1096 STARTUPINFOA startup;
1097 char* child_env;
1098 int child_env_len;
1099 char* ptr;
1100 char* env;
1101 int slen;
1102
1103 memset(&startup, 0, sizeof(startup));
1104 startup.cb = sizeof(startup);
1105 startup.dwFlags = STARTF_USESHOWWINDOW;
1106 startup.wShowWindow = SW_SHOWNORMAL;
1107
1108 /* the basics */
1109 get_file_name(resfile);
1110 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
1111 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
1112 /* wait for child to terminate */
1113 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1114 /* child process has changed result file, so let profile functions know about it */
1115 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1116
1117 cmpEnvironment(GetEnvironmentStringsA());
1118 release_memory();
1119 assert(DeleteFileA(resfile) != 0);
1120
1121 memset(&startup, 0, sizeof(startup));
1122 startup.cb = sizeof(startup);
1123 startup.dwFlags = STARTF_USESHOWWINDOW;
1124 startup.wShowWindow = SW_SHOWNORMAL;
1125
1126 /* the basics */
1127 get_file_name(resfile);
1128 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
1129
1130 child_env_len = 0;
1131 ptr = GetEnvironmentStringsA();
1132 while(*ptr)
1133 {
1134 slen = strlen(ptr)+1;
1135 child_env_len += slen;
1136 ptr += slen;
1137 }
1138 /* Add space for additional environment variables */
1139 child_env_len += 256;
1140 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
1141
1142 ptr = child_env;
1143 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
1144 ptr += strlen(ptr) + 1;
1145 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
1146 ptr += strlen(ptr) + 1;
1147 strcpy(ptr, "FOO=BAR");
1148 ptr += strlen(ptr) + 1;
1149 strcpy(ptr, "BAR=FOOBAR");
1150 ptr += strlen(ptr) + 1;
1151 /* copy all existing variables except:
1152 * - WINELOADER
1153 * - PATH (already set above)
1154 * - the directory definitions (=[A-Z]:=)
1155 */
1156 for (env = GetEnvironmentStringsA(); *env; env += strlen(env) + 1)
1157 {
1158 if (strncmp(env, "PATH=", 5) != 0 &&
1159 strncmp(env, "WINELOADER=", 11) != 0 &&
1160 !is_str_env_drive_dir(env))
1161 {
1162 strcpy(ptr, env);
1163 ptr += strlen(ptr) + 1;
1164 }
1165 }
1166 *ptr = '\0';
1167 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess\n");
1168 /* wait for child to terminate */
1169 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1170 /* child process has changed result file, so let profile functions know about it */
1171 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1172
1173 cmpEnvironment(child_env);
1174
1175 HeapFree(GetProcessHeap(), 0, child_env);
1176 release_memory();
1177 assert(DeleteFileA(resfile) != 0);
1178 }
1179
1180 static void test_SuspendFlag(void)
1181 {
1182 char buffer[MAX_PATH];
1183 PROCESS_INFORMATION info;
1184 STARTUPINFOA startup, us;
1185 DWORD exit_status;
1186
1187 /* let's start simplistic */
1188 memset(&startup, 0, sizeof(startup));
1189 startup.cb = sizeof(startup);
1190 startup.dwFlags = STARTF_USESHOWWINDOW;
1191 startup.wShowWindow = SW_SHOWNORMAL;
1192
1193 get_file_name(resfile);
1194 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
1195 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess\n");
1196
1197 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1198 Sleep(8000);
1199 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1200 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
1201
1202 /* wait for child to terminate */
1203 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1204 /* child process has changed result file, so let profile functions know about it */
1205 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1206
1207 GetStartupInfoA(&us);
1208
1209 okChildInt("StartupInfoA", "cb", startup.cb);
1210 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1211 ok (startup.lpTitle == NULL || !strcmp(startup.lpTitle, selfname),
1212 "StartupInfoA:lpTitle expected '%s' or null, got '%s'\n", selfname, startup.lpTitle);
1213 okChildInt("StartupInfoA", "dwX", startup.dwX);
1214 okChildInt("StartupInfoA", "dwY", startup.dwY);
1215 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1216 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1217 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1218 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1219 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1220 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1221 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1222 release_memory();
1223 assert(DeleteFileA(resfile) != 0);
1224 }
1225
1226 static void test_DebuggingFlag(void)
1227 {
1228 char buffer[MAX_PATH];
1229 void *processbase = NULL;
1230 PROCESS_INFORMATION info;
1231 STARTUPINFOA startup, us;
1232 DEBUG_EVENT de;
1233 unsigned dbg = 0;
1234
1235 /* let's start simplistic */
1236 memset(&startup, 0, sizeof(startup));
1237 startup.cb = sizeof(startup);
1238 startup.dwFlags = STARTF_USESHOWWINDOW;
1239 startup.wShowWindow = SW_SHOWNORMAL;
1240
1241 get_file_name(resfile);
1242 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
1243 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1244
1245 /* get all startup events up to the entry point break exception */
1246 do
1247 {
1248 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1249 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1250 if (!dbg)
1251 {
1252 ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1253 "first event: %d\n", de.dwDebugEventCode);
1254 processbase = de.u.CreateProcessInfo.lpBaseOfImage;
1255 }
1256 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
1257 ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT ||
1258 de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n");
1259 } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
1260
1261 ok(dbg, "I have seen a debug event\n");
1262 /* wait for child to terminate */
1263 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1264 /* child process has changed result file, so let profile functions know about it */
1265 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1266
1267 GetStartupInfoA(&us);
1268
1269 okChildInt("StartupInfoA", "cb", startup.cb);
1270 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1271 ok (startup.lpTitle == NULL || !strcmp(startup.lpTitle, selfname),
1272 "StartupInfoA:lpTitle expected '%s' or null, got '%s'\n", selfname, startup.lpTitle);
1273 okChildInt("StartupInfoA", "dwX", startup.dwX);
1274 okChildInt("StartupInfoA", "dwY", startup.dwY);
1275 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1276 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1277 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1278 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1279 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1280 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1281 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1282 release_memory();
1283 assert(DeleteFileA(resfile) != 0);
1284 }
1285
1286 static BOOL is_console(HANDLE h)
1287 {
1288 return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1289 }
1290
1291 static void test_Console(void)
1292 {
1293 char buffer[MAX_PATH];
1294 PROCESS_INFORMATION info;
1295 STARTUPINFOA startup, us;
1296 SECURITY_ATTRIBUTES sa;
1297 CONSOLE_SCREEN_BUFFER_INFO sbi, sbiC;
1298 DWORD modeIn, modeOut, modeInC, modeOutC;
1299 DWORD cpIn, cpOut, cpInC, cpOutC;
1300 DWORD w;
1301 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1302 const char* msg = "This is a std-handle inheritance test.";
1303 unsigned msg_len;
1304 BOOL run_tests = TRUE;
1305
1306 memset(&startup, 0, sizeof(startup));
1307 startup.cb = sizeof(startup);
1308 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1309 startup.wShowWindow = SW_SHOWNORMAL;
1310
1311 sa.nLength = sizeof(sa);
1312 sa.lpSecurityDescriptor = NULL;
1313 sa.bInheritHandle = TRUE;
1314
1315 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1316 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1317
1318 /* first, we need to be sure we're attached to a console */
1319 if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1320 {
1321 /* we're not attached to a console, let's do it */
1322 AllocConsole();
1323 startup.hStdInput = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1324 startup.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
1325 }
1326 /* now verify everything's ok */
1327 ok(startup.hStdInput != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1328 ok(startup.hStdOutput != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1329 startup.hStdError = startup.hStdOutput;
1330
1331 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
1332 ok(GetConsoleMode(startup.hStdInput, &modeIn) &&
1333 GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console modes\n");
1334 cpIn = GetConsoleCP();
1335 cpOut = GetConsoleOutputCP();
1336
1337 get_file_name(resfile);
1338 sprintf(buffer, "%s tests/process.c %s console", selfname, resfile);
1339 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1340
1341 /* wait for child to terminate */
1342 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1343 /* child process has changed result file, so let profile functions know about it */
1344 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1345
1346 /* now get the modification the child has made, and resets parents expected values */
1347 ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
1348 ok(GetConsoleMode(startup.hStdInput, &modeInC) &&
1349 GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console modes\n");
1350
1351 SetConsoleMode(startup.hStdInput, modeIn);
1352 SetConsoleMode(startup.hStdOutput, modeOut);
1353
1354 cpInC = GetConsoleCP();
1355 cpOutC = GetConsoleOutputCP();
1356
1357 /* Try to set invalid CP */
1358 SetLastError(0xdeadbeef);
1359 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1360 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1361 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1362 "GetLastError: expecting %u got %u\n",
1363 ERROR_INVALID_PARAMETER, GetLastError());
1364 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1365 run_tests = FALSE;
1366
1367
1368 SetLastError(0xdeadbeef);
1369 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1370 ok(GetLastError()==ERROR_INVALID_PARAMETER ||
1371 broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */
1372 "GetLastError: expecting %u got %u\n",
1373 ERROR_INVALID_PARAMETER, GetLastError());
1374
1375 SetConsoleCP(cpIn);
1376 SetConsoleOutputCP(cpOut);
1377
1378 GetStartupInfoA(&us);
1379
1380 okChildInt("StartupInfoA", "cb", startup.cb);
1381 okChildString("StartupInfoA", "lpDesktop", us.lpDesktop);
1382 ok (startup.lpTitle == NULL || !strcmp(startup.lpTitle, selfname),
1383 "StartupInfoA:lpTitle expected '%s' or null, got '%s'\n", selfname, startup.lpTitle);
1384 okChildInt("StartupInfoA", "dwX", startup.dwX);
1385 okChildInt("StartupInfoA", "dwY", startup.dwY);
1386 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
1387 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
1388 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
1389 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
1390 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
1391 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
1392 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
1393
1394 /* check child correctly inherited the console */
1395 okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput);
1396 okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput);
1397 okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError);
1398 okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X);
1399 okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y);
1400 okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X);
1401 okChildInt("Console", "CursorY", (DWORD)sbi.dwCursorPosition.Y);
1402 okChildInt("Console", "Attributes", sbi.wAttributes);
1403 okChildInt("Console", "winLeft", (DWORD)sbi.srWindow.Left);
1404 okChildInt("Console", "winTop", (DWORD)sbi.srWindow.Top);
1405 okChildInt("Console", "winRight", (DWORD)sbi.srWindow.Right);
1406 okChildInt("Console", "winBottom", (DWORD)sbi.srWindow.Bottom);
1407 okChildInt("Console", "maxWinWidth", (DWORD)sbi.dwMaximumWindowSize.X);
1408 okChildInt("Console", "maxWinHeight", (DWORD)sbi.dwMaximumWindowSize.Y);
1409 okChildInt("Console", "InputCP", cpIn);
1410 okChildInt("Console", "OutputCP", cpOut);
1411 okChildInt("Console", "InputMode", modeIn);
1412 okChildInt("Console", "OutputMode", modeOut);
1413
1414 if (run_tests)
1415 {
1416 ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn);
1417 ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut);
1418 }
1419 else
1420 win_skip("Setting the codepage is not implemented\n");
1421
1422 ok(modeInC == (modeIn ^ 1), "Wrong console mode\n");
1423 ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n");
1424 trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X);
1425 ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
1426
1427 release_memory();
1428 assert(DeleteFileA(resfile) != 0);
1429
1430 ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
1431 ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(),
1432 &hChildOutInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1433 "Duplicating as inheritable child-output pipe\n");
1434 CloseHandle(hChildOut);
1435
1436 ok(CreatePipe(&hChildIn, &hParentOut, NULL, 0), "Creating parent-output pipe\n");
1437 ok(DuplicateHandle(GetCurrentProcess(), hChildIn, GetCurrentProcess(),
1438 &hChildInInh, 0, TRUE, DUPLICATE_SAME_ACCESS),
1439 "Duplicating as inheritable child-input pipe\n");
1440 CloseHandle(hChildIn);
1441
1442 memset(&startup, 0, sizeof(startup));
1443 startup.cb = sizeof(startup);
1444 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1445 startup.wShowWindow = SW_SHOWNORMAL;
1446 startup.hStdInput = hChildInInh;
1447 startup.hStdOutput = hChildOutInh;
1448 startup.hStdError = hChildOutInh;
1449
1450 get_file_name(resfile);
1451 sprintf(buffer, "%s tests/process.c %s stdhandle", selfname, resfile);
1452 ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, &info), "CreateProcess\n");
1453 ok(CloseHandle(hChildInInh), "Closing handle\n");
1454 ok(CloseHandle(hChildOutInh), "Closing handle\n");
1455
1456 msg_len = strlen(msg) + 1;
1457 ok(WriteFile(hParentOut, msg, msg_len, &w, NULL), "Writing to child\n");
1458 ok(w == msg_len, "Should have written %u bytes, actually wrote %u\n", msg_len, w);
1459 memset(buffer, 0, sizeof(buffer));
1460 ok(ReadFile(hParentIn, buffer, sizeof(buffer), &w, NULL), "Reading from child\n");
1461 ok(strcmp(buffer, msg) == 0, "Should have received '%s'\n", msg);
1462
1463 /* wait for child to terminate */
1464 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1465 /* child process has changed result file, so let profile functions know about it */
1466 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1467
1468 okChildString("StdHandle", "msg", msg);
1469
1470 release_memory();
1471 assert(DeleteFileA(resfile) != 0);
1472 }
1473
1474 static void test_ExitCode(void)
1475 {
1476 char buffer[MAX_PATH];
1477 PROCESS_INFORMATION info;
1478 STARTUPINFOA startup;
1479 DWORD code;
1480
1481 /* let's start simplistic */
1482 memset(&startup, 0, sizeof(startup));
1483 startup.cb = sizeof(startup);
1484 startup.dwFlags = STARTF_USESHOWWINDOW;
1485 startup.wShowWindow = SW_SHOWNORMAL;
1486
1487 get_file_name(resfile);
1488 sprintf(buffer, "%s tests/process.c %s exit_code", selfname, resfile);
1489 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess\n");
1490
1491 /* wait for child to terminate */
1492 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
1493 /* child process has changed result file, so let profile functions know about it */
1494 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
1495
1496 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1497 okChildInt("ExitCode", "value", code);
1498
1499 release_memory();
1500 assert(DeleteFileA(resfile) != 0);
1501 }
1502
1503 static void test_OpenProcess(void)
1504 {
1505 HANDLE hproc;
1506 void *addr1;
1507 MEMORY_BASIC_INFORMATION info;
1508 SIZE_T dummy, read_bytes;
1509
1510 /* not exported in all windows versions */
1511 if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1512 win_skip("VirtualAllocEx not found\n");
1513 return;
1514 }
1515
1516 /* without PROCESS_VM_OPERATION */
1517 hproc = OpenProcess(PROCESS_ALL_ACCESS & ~PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1518 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1519
1520 SetLastError(0xdeadbeef);
1521 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1522 ok(!addr1, "VirtualAllocEx should fail\n");
1523 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1524 { /* Win9x */
1525 CloseHandle(hproc);
1526 win_skip("VirtualAllocEx not implemented\n");
1527 return;
1528 }
1529 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1530
1531 read_bytes = 0xdeadbeef;
1532 SetLastError(0xdeadbeef);
1533 ok(ReadProcessMemory(hproc, test_OpenProcess, &dummy, sizeof(dummy), &read_bytes),
1534 "ReadProcessMemory error %d\n", GetLastError());
1535 ok(read_bytes == sizeof(dummy), "wrong read bytes %ld\n", read_bytes);
1536
1537 CloseHandle(hproc);
1538
1539 hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1540 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1541
1542 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1543 ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
1544
1545 /* without PROCESS_QUERY_INFORMATION */
1546 SetLastError(0xdeadbeef);
1547 ok(!VirtualQueryEx(hproc, addr1, &info, sizeof(info)),
1548 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1549 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1550
1551 /* without PROCESS_VM_READ */
1552 read_bytes = 0xdeadbeef;
1553 SetLastError(0xdeadbeef);
1554 ok(!ReadProcessMemory(hproc, addr1, &dummy, sizeof(dummy), &read_bytes),
1555 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1556 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1557 ok(read_bytes == 0, "wrong read bytes %ld\n", read_bytes);
1558
1559 CloseHandle(hproc);
1560
1561 hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1562
1563 memset(&info, 0xcc, sizeof(info));
1564 ok(VirtualQueryEx(hproc, addr1, &info, sizeof(info)) == sizeof(info),
1565 "VirtualQueryEx error %d\n", GetLastError());
1566
1567 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
1568 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
1569 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
1570 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
1571 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
1572 /* NT reports Protect == 0 for a not committed memory block */
1573 ok(info.Protect == 0 /* NT */ ||
1574 info.Protect == PAGE_NOACCESS, /* Win9x */
1575 "%x != PAGE_NOACCESS\n", info.Protect);
1576 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
1577
1578 SetLastError(0xdeadbeef);
1579 ok(!pVirtualFreeEx(hproc, addr1, 0, MEM_RELEASE),
1580 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1581 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
1582
1583 CloseHandle(hproc);
1584
1585 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1586 }
1587
1588 static void test_GetProcessVersion(void)
1589 {
1590 static char cmdline[] = "winver.exe";
1591 PROCESS_INFORMATION pi;
1592 STARTUPINFOA si;
1593 DWORD ret;
1594
1595 SetLastError(0xdeadbeef);
1596 ret = GetProcessVersion(0);
1597 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1598
1599 SetLastError(0xdeadbeef);
1600 ret = GetProcessVersion(GetCurrentProcessId());
1601 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1602
1603 memset(&si, 0, sizeof(si));
1604 si.cb = sizeof(si);
1605 si.dwFlags = STARTF_USESHOWWINDOW;
1606 si.wShowWindow = SW_HIDE;
1607 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1608 SetLastError(0xdeadbeef);
1609 ok(ret, "CreateProcess error %u\n", GetLastError());
1610
1611 SetLastError(0xdeadbeef);
1612 ret = GetProcessVersion(pi.dwProcessId);
1613 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1614
1615 SetLastError(0xdeadbeef);
1616 ret = TerminateProcess(pi.hProcess, 0);
1617 ok(ret, "TerminateProcess error %u\n", GetLastError());
1618
1619 CloseHandle(pi.hProcess);
1620 CloseHandle(pi.hThread);
1621 }
1622
1623 static void test_ProcessNameA(void)
1624 {
1625 #define INIT_STR "Just some words"
1626 DWORD length, size;
1627 CHAR buf[1024];
1628
1629 if (!pQueryFullProcessImageNameA)
1630 {
1631 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1632 return;
1633 }
1634 /* get the buffer length without \0 terminator */
1635 length = 1024;
1636 expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length));
1637 expect_eq_d(length, lstrlenA(buf));
1638
1639 /* when the buffer is too small
1640 * - function fail with error ERROR_INSUFFICIENT_BUFFER
1641 * - the size variable is not modified
1642 * tested with the biggest too small size
1643 */
1644 size = length;
1645 sprintf(buf,INIT_STR);
1646 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1647 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1648 expect_eq_d(length, size);
1649 expect_eq_s(INIT_STR, buf);
1650
1651 /* retest with smaller buffer size
1652 */
1653 size = 4;
1654 sprintf(buf,INIT_STR);
1655 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size));
1656 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1657 expect_eq_d(4, size);
1658 expect_eq_s(INIT_STR, buf);
1659
1660 /* this is a difference between the ascii and the unicode version
1661 * the unicode version crashes when the size is big enough to hold the result
1662 * ascii version throughs an error
1663 */
1664 size = 1024;
1665 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1666 expect_eq_d(1024, size);
1667 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
1668 }
1669
1670 static void test_ProcessName(void)
1671 {
1672 HANDLE hSelf;
1673 WCHAR module_name[1024];
1674 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
1675 WCHAR buf[1024];
1676 DWORD size;
1677
1678 if (!pQueryFullProcessImageNameW)
1679 {
1680 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1681 return;
1682 }
1683
1684 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
1685
1686 /* GetCurrentProcess pseudo-handle */
1687 size = sizeof(buf) / sizeof(buf[0]);
1688 expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size));
1689 expect_eq_d(lstrlenW(buf), size);
1690 expect_eq_ws_i(buf, module_name);
1691
1692 hSelf = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
1693 /* Real handle */
1694 size = sizeof(buf) / sizeof(buf[0]);
1695 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1696 expect_eq_d(lstrlenW(buf), size);
1697 expect_eq_ws_i(buf, module_name);
1698
1699 /* Buffer too small */
1700 size = lstrlenW(module_name)/2;
1701 lstrcpyW(buf, deviceW);
1702 SetLastError(0xdeadbeef);
1703 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1704 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
1705 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1706 expect_eq_ws_i(deviceW, buf); /* buffer not changed */
1707
1708 /* Too small - not space for NUL terminator */
1709 size = lstrlenW(module_name);
1710 SetLastError(0xdeadbeef);
1711 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1712 expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */
1713 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1714
1715 /* NULL buffer */
1716 size = 0;
1717 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
1718 expect_eq_d(0, size);
1719 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1720
1721 /* native path */
1722 size = sizeof(buf) / sizeof(buf[0]);
1723 expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size));
1724 expect_eq_d(lstrlenW(buf), size);
1725 ok(buf[0] == '\\', "NT path should begin with '\\'\n");
1726 todo_wine ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n");
1727
1728 /* Buffer too small */
1729 size = lstrlenW(module_name)/2;
1730 SetLastError(0xdeadbeef);
1731 lstrcpyW(buf, module_name);
1732 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
1733 expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */
1734 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
1735 expect_eq_ws_i(module_name, buf); /* buffer not changed */
1736
1737 CloseHandle(hSelf);
1738 }
1739
1740 static void test_Handles(void)
1741 {
1742 HANDLE handle = GetCurrentProcess();
1743 BOOL ret;
1744 DWORD code;
1745
1746 ok( handle == (HANDLE)~(ULONG_PTR)0 ||
1747 handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */,
1748 "invalid current process handle %p\n", handle );
1749 ret = GetExitCodeProcess( handle, &code );
1750 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
1751 #ifdef _WIN64
1752 /* truncated handle */
1753 SetLastError( 0xdeadbeef );
1754 handle = (HANDLE)((ULONG_PTR)handle & ~0u);
1755 ret = GetExitCodeProcess( handle, &code );
1756 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
1757 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
1758 /* sign-extended handle */
1759 SetLastError( 0xdeadbeef );
1760 handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle);
1761 ret = GetExitCodeProcess( handle, &code );
1762 ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() );
1763 /* invalid high-word */
1764 SetLastError( 0xdeadbeef );
1765 handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32));
1766 ret = GetExitCodeProcess( handle, &code );
1767 ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle );
1768 ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
1769 #endif
1770 }
1771
1772 START_TEST(process)
1773 {
1774 int b = init();
1775 ok(b, "Basic init of CreateProcess test\n");
1776 if (!b) return;
1777
1778 if (myARGC >= 3)
1779 {
1780 doChild(myARGV[2], (myARGC == 3) ? NULL : myARGV[3]);
1781 return;
1782 }
1783 test_Startup();
1784 test_CommandLine();
1785 test_Directory();
1786 test_Environment();
1787 test_SuspendFlag();
1788 test_DebuggingFlag();
1789 test_Console();
1790 test_ExitCode();
1791 test_OpenProcess();
1792 test_GetProcessVersion();
1793 test_ProcessNameA();
1794 test_ProcessName();
1795 test_Handles();
1796 /* things that can be tested:
1797 * lookup: check the way program to be executed is searched
1798 * handles: check the handle inheritance stuff (+sec options)
1799 * console: check if console creation parameters work
1800 */
1801 }