2 * Unit test suite for CreateProcess function.
4 * Copyright 2002 Eric Pouech
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "wine/test.h"
29 static char base[MAX_PATH];
30 static char selfname[MAX_PATH];
31 static char resfile[MAX_PATH];
36 /* as some environment variables get very long on Unix, we only test for
39 #define MAX_LISTED_ENV_VAR 128
41 /* ---------------- portable memory allocation thingie */
43 static char memory[1024*32];
44 static char* memory_index = memory;
46 static char* grab_memory(size_t len)
48 char* ret = memory_index;
52 assert(memory_index <= memory + sizeof(memory));
56 static void release_memory(void)
58 memory_index = memory;
61 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
63 static char* encodeA(const char* str)
69 len = strlen(str) + 1;
70 ptr = grab_memory(len * 2 + 1);
71 for (i = 0; i < len; i++)
72 sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
77 static char* encodeW(const WCHAR* str)
83 len = lstrlenW(str) + 1;
84 ptr = grab_memory(len * 4 + 1);
86 for (i = 0; i < len; i++)
87 sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
92 static unsigned decode_char(char c)
94 if (c >= '0' && c <= '9') return c - '0';
95 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
96 assert(c >= 'A' && c <= 'F');
100 static char* decodeA(const char* str)
105 len = strlen(str) / 2;
106 if (!len--) return NULL;
107 ptr = grab_memory(len + 1);
108 for (i = 0; i < len; i++)
109 ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
115 /* This will be needed to decode Unicode strings saved by the child process
116 * when we test Unicode functions.
118 static WCHAR* decodeW(const char* str)
124 len = strlen(str) / 4;
125 if (!len--) return NULL;
126 ptr = (WCHAR*)grab_memory(len * 2 + 1);
127 for (i = 0; i < len; i++)
128 ptr[i] = (decode_char(str[4 * i]) << 12) |
129 (decode_char(str[4 * i + 1]) << 8) |
130 (decode_char(str[4 * i + 2]) << 4) |
131 (decode_char(str[4 * i + 3]) << 0);
137 /******************************************************************
140 * generates basic information like:
141 * base: absolute path to curr dir
142 * selfname: the way to reinvoke ourselves
144 static int init(void)
146 myARGC = winetest_get_mainargs( &myARGV );
147 if (!GetCurrentDirectoryA(sizeof(base), base)) return 0;
148 strcpy(selfname, myARGV[0]);
152 /******************************************************************
155 * generates an absolute file_name for temporary file
158 static void get_file_name(char* buf)
163 GetTempPathA(sizeof(path), path);
164 GetTempFileNameA(path, "wt", 0, buf);
167 /******************************************************************
168 * static void childPrintf
171 static void childPrintf(HANDLE h, const char* fmt, ...)
177 va_start(valist, fmt);
178 vsprintf(buffer, fmt, valist);
180 WriteFile(h, buffer, strlen(buffer), &w, NULL);
184 /******************************************************************
187 * output most of the information in the child process
189 static void doChild(const char* file)
197 WCHAR bufW[MAX_PATH];
198 HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
200 if (hFile == INVALID_HANDLE_VALUE) return;
202 /* output of startup info (Ansi) */
203 GetStartupInfoA(&siA);
205 "[StartupInfoA]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
206 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
207 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
208 "dwFlags=%lu\nwShowWindow=%u\n"
209 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
210 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
211 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize,
212 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute,
213 siA.dwFlags, siA.wShowWindow,
214 (DWORD)siA.hStdInput, (DWORD)siA.hStdOutput, (DWORD)siA.hStdError);
216 /* since GetStartupInfoW is only implemented in win2k,
217 * zero out before calling so we can notice the difference
219 memset(&siW, 0, sizeof(siW));
220 GetStartupInfoW(&siW);
222 "[StartupInfoW]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
223 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
224 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
225 "dwFlags=%lu\nwShowWindow=%u\n"
226 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
227 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
228 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize,
229 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute,
230 siW.dwFlags, siW.wShowWindow,
231 (DWORD)siW.hStdInput, (DWORD)siW.hStdOutput, (DWORD)siW.hStdError);
234 childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
235 for (i = 0; i < myARGC; i++)
237 childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
239 childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
245 /* this is part of shell32... and should be tested there */
246 argvW = CommandLineToArgvW(GetCommandLineW(), &argcW);
247 for (i = 0; i < argcW; i++)
249 childPrintf(hFile, "argvW%d=%s\n", i, encodeW(argvW[i]));
252 childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
254 /* output of environment (Ansi) */
255 ptrA = GetEnvironmentStringsA();
258 char env_var[MAX_LISTED_ENV_VAR];
260 childPrintf(hFile, "[EnvironmentA]\n");
264 strncpy(env_var, ptrA, MAX_LISTED_ENV_VAR - 1);
265 env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
266 childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
268 ptrA += strlen(ptrA) + 1;
270 childPrintf(hFile, "len=%d\n\n", i);
273 /* output of environment (Unicode) */
274 ptrW = GetEnvironmentStringsW();
277 WCHAR env_var[MAX_LISTED_ENV_VAR];
279 childPrintf(hFile, "[EnvironmentW]\n");
283 lstrcpynW(env_var, ptrW, MAX_LISTED_ENV_VAR - 1);
284 env_var[MAX_LISTED_ENV_VAR - 1] = '\0';
285 childPrintf(hFile, "env%d=%s\n", i, encodeW(ptrW));
287 ptrW += lstrlenW(ptrW) + 1;
289 childPrintf(hFile, "len=%d\n\n", i);
292 childPrintf(hFile, "[Misc]\n");
293 if (GetCurrentDirectoryA(sizeof(bufA), bufA))
294 childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
295 if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW))
296 childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
297 childPrintf(hFile, "\n");
302 static char* getChildString(const char* sect, const char* key)
307 GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
308 if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
309 assert(!(strlen(buf) & 1));
314 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
315 * others... (windows uses stricmp while Un*x uses strcasecmp...)
317 static int wtstrcasecmp(const char* p1, const char* p2)
322 while (c1 == c2 && c1)
324 c1 = *p1++; c2 = *p2++;
327 c1 = toupper(c1); c2 = toupper(c2);
333 static int strCmp(const char* s1, const char* s2, BOOL sensitive)
335 if (!s1 && !s2) return 0;
338 return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2);
341 #define okChildString(sect, key, expect) \
343 char* result = getChildString((sect), (key)); \
344 ok(strCmp(result, expect, 1) == 0, "%s:%s expected %s, got %s", (sect), (key), (expect)?(expect):"(null)", result); \
347 #define okChildIString(sect, key, expect) \
349 char* result = getChildString(sect, key); \
350 ok(strCmp(result, expect, 0) == 0, "%s:%s expected %s, got %s", sect, key, expect, result); \
353 /* using !expect insures that the test will fail if the sect/key isn't present
356 #define okChildInt(sect, key, expect) \
358 UINT result = GetPrivateProfileIntA((sect), (key), !(expect), resfile); \
359 ok(result == expect, "%s:%s expected %d, but got %d\n", (sect), (key), (int)(expect), result); \
362 static void test_Startup(void)
364 char buffer[MAX_PATH];
365 PROCESS_INFORMATION info;
366 STARTUPINFOA startup,si;
368 /* let's start simplistic */
369 memset(&startup, 0, sizeof(startup));
370 startup.cb = sizeof(startup);
371 startup.dwFlags = STARTF_USESHOWWINDOW;
372 startup.wShowWindow = SW_SHOWNORMAL;
374 get_file_name(resfile);
375 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
376 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
377 /* wait for child to terminate */
378 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
379 /* child process has changed result file, so let profile functions know about it */
380 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
382 GetStartupInfoA(&si);
383 okChildInt("StartupInfoA", "cb", startup.cb);
384 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
385 okChildString("StartupInfoA", "lpTitle", si.lpTitle);
386 okChildInt("StartupInfoA", "dwX", startup.dwX);
387 okChildInt("StartupInfoA", "dwY", startup.dwY);
388 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
389 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
390 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
391 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
392 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
393 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
394 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
396 assert(DeleteFileA(resfile) != 0);
398 /* not so simplistic now */
399 memset(&startup, 0, sizeof(startup));
400 startup.cb = sizeof(startup);
401 startup.dwFlags = STARTF_USESHOWWINDOW;
402 startup.wShowWindow = SW_SHOWNORMAL;
403 startup.lpTitle = "I'm the title string";
404 startup.lpDesktop = "I'm the desktop string";
405 startup.dwXCountChars = 0x12121212;
406 startup.dwYCountChars = 0x23232323;
407 startup.dwX = 0x34343434;
408 startup.dwY = 0x45454545;
409 startup.dwXSize = 0x56565656;
410 startup.dwYSize = 0x67676767;
411 startup.dwFillAttribute = 0xA55A;
413 get_file_name(resfile);
414 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
415 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
416 /* wait for child to terminate */
417 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
418 /* child process has changed result file, so let profile functions know about it */
419 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
421 okChildInt("StartupInfoA", "cb", startup.cb);
422 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
423 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
424 okChildInt("StartupInfoA", "dwX", startup.dwX);
425 okChildInt("StartupInfoA", "dwY", startup.dwY);
426 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
427 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
428 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
429 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
430 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
431 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
432 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
434 assert(DeleteFileA(resfile) != 0);
436 /* not so simplistic now */
437 memset(&startup, 0, sizeof(startup));
438 startup.cb = sizeof(startup);
439 startup.dwFlags = STARTF_USESHOWWINDOW;
440 startup.wShowWindow = SW_SHOWNORMAL;
441 startup.lpTitle = "I'm the title string";
442 startup.lpDesktop = NULL;
443 startup.dwXCountChars = 0x12121212;
444 startup.dwYCountChars = 0x23232323;
445 startup.dwX = 0x34343434;
446 startup.dwY = 0x45454545;
447 startup.dwXSize = 0x56565656;
448 startup.dwYSize = 0x67676767;
449 startup.dwFillAttribute = 0xA55A;
451 get_file_name(resfile);
452 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
453 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
454 /* wait for child to terminate */
455 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
456 /* child process has changed result file, so let profile functions know about it */
457 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
459 okChildInt("StartupInfoA", "cb", startup.cb);
460 okChildString("StartupInfoA", "lpDesktop", si.lpDesktop);
461 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
462 okChildInt("StartupInfoA", "dwX", startup.dwX);
463 okChildInt("StartupInfoA", "dwY", startup.dwY);
464 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
465 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
466 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
467 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
468 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
469 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
470 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
472 assert(DeleteFileA(resfile) != 0);
474 /* not so simplistic now */
475 memset(&startup, 0, sizeof(startup));
476 startup.cb = sizeof(startup);
477 startup.dwFlags = STARTF_USESHOWWINDOW;
478 startup.wShowWindow = SW_SHOWNORMAL;
479 startup.lpTitle = "I'm the title string";
480 startup.lpDesktop = "";
481 startup.dwXCountChars = 0x12121212;
482 startup.dwYCountChars = 0x23232323;
483 startup.dwX = 0x34343434;
484 startup.dwY = 0x45454545;
485 startup.dwXSize = 0x56565656;
486 startup.dwYSize = 0x67676767;
487 startup.dwFillAttribute = 0xA55A;
489 get_file_name(resfile);
490 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
491 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
492 /* wait for child to terminate */
493 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
494 /* child process has changed result file, so let profile functions know about it */
495 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
497 okChildInt("StartupInfoA", "cb", startup.cb);
498 todo_wine okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
499 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
500 okChildInt("StartupInfoA", "dwX", startup.dwX);
501 okChildInt("StartupInfoA", "dwY", startup.dwY);
502 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
503 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
504 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
505 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
506 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
507 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
508 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
510 assert(DeleteFileA(resfile) != 0);
512 /* not so simplistic now */
513 memset(&startup, 0, sizeof(startup));
514 startup.cb = sizeof(startup);
515 startup.dwFlags = STARTF_USESHOWWINDOW;
516 startup.wShowWindow = SW_SHOWNORMAL;
517 startup.lpTitle = NULL;
518 startup.lpDesktop = "I'm the desktop string";
519 startup.dwXCountChars = 0x12121212;
520 startup.dwYCountChars = 0x23232323;
521 startup.dwX = 0x34343434;
522 startup.dwY = 0x45454545;
523 startup.dwXSize = 0x56565656;
524 startup.dwYSize = 0x67676767;
525 startup.dwFillAttribute = 0xA55A;
527 get_file_name(resfile);
528 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
529 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
530 /* wait for child to terminate */
531 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
532 /* child process has changed result file, so let profile functions know about it */
533 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
535 okChildInt("StartupInfoA", "cb", startup.cb);
536 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
537 okChildString("StartupInfoA", "lpTitle", si.lpTitle);
538 okChildInt("StartupInfoA", "dwX", startup.dwX);
539 okChildInt("StartupInfoA", "dwY", startup.dwY);
540 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
541 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
542 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
543 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
544 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
545 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
546 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
548 assert(DeleteFileA(resfile) != 0);
550 /* not so simplistic now */
551 memset(&startup, 0, sizeof(startup));
552 startup.cb = sizeof(startup);
553 startup.dwFlags = STARTF_USESHOWWINDOW;
554 startup.wShowWindow = SW_SHOWNORMAL;
555 startup.lpTitle = "";
556 startup.lpDesktop = "I'm the desktop string";
557 startup.dwXCountChars = 0x12121212;
558 startup.dwYCountChars = 0x23232323;
559 startup.dwX = 0x34343434;
560 startup.dwY = 0x45454545;
561 startup.dwXSize = 0x56565656;
562 startup.dwYSize = 0x67676767;
563 startup.dwFillAttribute = 0xA55A;
565 get_file_name(resfile);
566 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
567 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
568 /* wait for child to terminate */
569 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
570 /* child process has changed result file, so let profile functions know about it */
571 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
573 okChildInt("StartupInfoA", "cb", startup.cb);
574 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
575 todo_wine okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
576 okChildInt("StartupInfoA", "dwX", startup.dwX);
577 okChildInt("StartupInfoA", "dwY", startup.dwY);
578 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
579 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
580 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
581 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
582 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
583 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
584 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
586 assert(DeleteFileA(resfile) != 0);
588 /* not so simplistic now */
589 memset(&startup, 0, sizeof(startup));
590 startup.cb = sizeof(startup);
591 startup.dwFlags = STARTF_USESHOWWINDOW;
592 startup.wShowWindow = SW_SHOWNORMAL;
593 startup.lpTitle = "";
594 startup.lpDesktop = "";
595 startup.dwXCountChars = 0x12121212;
596 startup.dwYCountChars = 0x23232323;
597 startup.dwX = 0x34343434;
598 startup.dwY = 0x45454545;
599 startup.dwXSize = 0x56565656;
600 startup.dwYSize = 0x67676767;
601 startup.dwFillAttribute = 0xA55A;
603 get_file_name(resfile);
604 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
605 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
606 /* wait for child to terminate */
607 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
608 /* child process has changed result file, so let profile functions know about it */
609 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
611 okChildInt("StartupInfoA", "cb", startup.cb);
612 todo_wine okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
613 todo_wine okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
614 okChildInt("StartupInfoA", "dwX", startup.dwX);
615 okChildInt("StartupInfoA", "dwY", startup.dwY);
616 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
617 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
618 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
619 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
620 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
621 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
622 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
624 assert(DeleteFileA(resfile) != 0);
626 /* TODO: test for A/W and W/A and W/W */
629 static void test_CommandLine(void)
631 char buffer[MAX_PATH];
632 PROCESS_INFORMATION info;
633 STARTUPINFOA startup;
635 memset(&startup, 0, sizeof(startup));
636 startup.cb = sizeof(startup);
637 startup.dwFlags = STARTF_USESHOWWINDOW;
638 startup.wShowWindow = SW_SHOWNORMAL;
641 get_file_name(resfile);
642 sprintf(buffer, "%s tests/process.c %s \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
643 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
644 /* wait for child to terminate */
645 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
646 /* child process has changed result file, so let profile functions know about it */
647 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
649 okChildInt("Arguments", "argcA", 4);
650 okChildString("Arguments", "argvA3", "C:\\Program Files\\my nice app.exe");
651 okChildString("Arguments", "argvA4", NULL);
652 okChildString("Arguments", "CommandLineA", buffer);
654 assert(DeleteFileA(resfile) != 0);
656 memset(&startup, 0, sizeof(startup));
657 startup.cb = sizeof(startup);
658 startup.dwFlags = STARTF_USESHOWWINDOW;
659 startup.wShowWindow = SW_SHOWNORMAL;
662 get_file_name(resfile);
663 sprintf(buffer, "%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
664 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
665 /* wait for child to terminate */
666 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
667 /* child process has changed result file, so let profile functions know about it */
668 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
670 okChildInt("Arguments", "argcA", 6);
671 okChildString("Arguments", "argvA3", "a\"b\\");
672 okChildString("Arguments", "argvA4", "c\"");
673 okChildString("Arguments", "argvA5", "d");
674 okChildString("Arguments", "argvA6", NULL);
675 okChildString("Arguments", "CommandLineA", buffer);
677 assert(DeleteFileA(resfile) != 0);
680 static void test_Directory(void)
682 char buffer[MAX_PATH];
683 PROCESS_INFORMATION info;
684 STARTUPINFOA startup;
685 char windir[MAX_PATH];
687 memset(&startup, 0, sizeof(startup));
688 startup.cb = sizeof(startup);
689 startup.dwFlags = STARTF_USESHOWWINDOW;
690 startup.wShowWindow = SW_SHOWNORMAL;
693 get_file_name(resfile);
694 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
695 GetWindowsDirectoryA( windir, sizeof(windir) );
696 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess");
697 /* wait for child to terminate */
698 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
699 /* child process has changed result file, so let profile functions know about it */
700 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
702 okChildIString("Misc", "CurrDirA", windir);
704 assert(DeleteFileA(resfile) != 0);
707 static BOOL is_str_env_drive_dir(const char* str)
709 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
710 str[3] == '=' && str[4] == str[1];
713 /* compared expected child's environment (in gesA) from actual
714 * environment our child got
716 static void cmpEnvironment(const char* gesA)
724 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
726 /* now look each parent env in child */
727 if ((ptrA = gesA) != NULL)
731 for (i = 0; i < clen; i++)
733 sprintf(key, "env%d", i);
734 res = getChildString("EnvironmentA", key);
735 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
739 ok(found, "Parent-env string %s isn't in child process", ptrA);
741 ptrA += strlen(ptrA) + 1;
745 /* and each child env in parent */
746 for (i = 0; i < clen; i++)
748 sprintf(key, "env%d", i);
749 res = getChildString("EnvironmentA", key);
750 if ((ptrA = gesA) != NULL)
754 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
756 ptrA += strlen(ptrA) + 1;
758 if (!*ptrA) ptrA = NULL;
761 if (!is_str_env_drive_dir(res))
763 found = ptrA != NULL;
764 ok(found, "Child-env string %s isn't in parent process", res);
766 /* else => should also test we get the right per drive default directory here... */
770 static void test_Environment(void)
772 char buffer[MAX_PATH];
773 PROCESS_INFORMATION info;
774 STARTUPINFOA startup;
775 char child_env[4096];
779 memset(&startup, 0, sizeof(startup));
780 startup.cb = sizeof(startup);
781 startup.dwFlags = STARTF_USESHOWWINDOW;
782 startup.wShowWindow = SW_SHOWNORMAL;
785 get_file_name(resfile);
786 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
787 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
788 /* wait for child to terminate */
789 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
790 /* child process has changed result file, so let profile functions know about it */
791 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
793 cmpEnvironment(GetEnvironmentStringsA());
795 assert(DeleteFileA(resfile) != 0);
797 memset(&startup, 0, sizeof(startup));
798 startup.cb = sizeof(startup);
799 startup.dwFlags = STARTF_USESHOWWINDOW;
800 startup.wShowWindow = SW_SHOWNORMAL;
803 get_file_name(resfile);
804 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
806 sprintf(ptr, "=%c:=%s", 'C', "C:\\FOO\\BAR");
807 ptr += strlen(ptr) + 1;
808 strcpy(ptr, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
809 ptr += strlen(ptr) + 1;
810 strcpy(ptr, "FOO=BAR");
811 ptr += strlen(ptr) + 1;
812 strcpy(ptr, "BAR=FOOBAR");
813 ptr += strlen(ptr) + 1;
814 /* copy all existing variables except:
816 * - PATH (already set above)
817 * - the directory definitions (=[A-Z]:=)
819 for (env = GetEnvironmentStringsA(); *env; env += strlen(env) + 1)
821 if (strncmp(env, "PATH=", 5) != 0 &&
822 strncmp(env, "WINELOADER=", 11) != 0 &&
823 !is_str_env_drive_dir(env))
826 ptr += strlen(ptr) + 1;
830 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, child_env, NULL, &startup, &info), "CreateProcess");
831 /* wait for child to terminate */
832 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
833 /* child process has changed result file, so let profile functions know about it */
834 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
836 cmpEnvironment(child_env);
839 assert(DeleteFileA(resfile) != 0);
842 static void test_SuspendFlag(void)
844 char buffer[MAX_PATH];
845 PROCESS_INFORMATION info;
846 STARTUPINFOA startup;
849 /* let's start simplistic */
850 memset(&startup, 0, sizeof(startup));
851 startup.cb = sizeof(startup);
852 startup.dwFlags = STARTF_USESHOWWINDOW;
853 startup.wShowWindow = SW_SHOWNORMAL;
855 get_file_name(resfile);
856 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
857 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startup, &info), "CreateProcess");
859 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running");
861 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running");
862 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
864 /* wait for child to terminate */
865 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
866 /* child process has changed result file, so let profile functions know about it */
867 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
869 okChildInt("StartupInfoA", "cb", startup.cb);
870 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
871 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
872 okChildInt("StartupInfoA", "dwX", startup.dwX);
873 okChildInt("StartupInfoA", "dwY", startup.dwY);
874 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
875 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
876 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
877 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
878 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
879 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
880 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
882 assert(DeleteFileA(resfile) != 0);
885 static void test_DebuggingFlag(void)
887 char buffer[MAX_PATH];
888 PROCESS_INFORMATION info;
889 STARTUPINFOA startup;
893 /* let's start simplistic */
894 memset(&startup, 0, sizeof(startup));
895 startup.cb = sizeof(startup);
896 startup.dwFlags = STARTF_USESHOWWINDOW;
897 startup.wShowWindow = SW_SHOWNORMAL;
899 get_file_name(resfile);
900 sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
901 ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &startup, &info), "CreateProcess");
903 /* get all startup events up to the entry point break exception */
906 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event");
907 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
908 if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++;
909 } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
911 ok(dbg, "I have seen a debug event");
912 /* wait for child to terminate */
913 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
914 /* child process has changed result file, so let profile functions know about it */
915 WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
917 okChildInt("StartupInfoA", "cb", startup.cb);
918 okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
919 okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
920 okChildInt("StartupInfoA", "dwX", startup.dwX);
921 okChildInt("StartupInfoA", "dwY", startup.dwY);
922 okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
923 okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
924 okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
925 okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
926 okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
927 okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
928 okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
930 assert(DeleteFileA(resfile) != 0);
936 ok(b, "Basic init of CreateProcess test");
949 test_DebuggingFlag();
950 /* things that can be tested:
951 * lookup: check the way program to be executed is searched
952 * handles: check the handle inheritance stuff (+sec options)
953 * console: check if console creation parameters work