Better implementation of GetCalendarInfo{A,W}, not perfect.
[wine] / dlls / kernel / tests / process.c
1 /*
2  * Unit test suite for CreateProcess function.
3  *
4  * Copyright 2002 Eric Pouech
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "wine/test.h"
27
28 static char     base[MAX_PATH];
29 static char     selfname[MAX_PATH];
30 static char     resfile[MAX_PATH];
31
32 static int      myARGC;
33 static char**   myARGV;
34
35 /* ---------------- portable memory allocation thingie */
36
37 static char     memory[16384];
38 static char*    memory_index = memory;
39
40 static char*    grab_memory(size_t len)
41 {
42     char*       ret = memory_index;
43     /* align on dword */
44     len = (len + 3) & ~3;
45     memory_index += len;
46     assert(memory_index <= memory + sizeof(memory));
47     return ret;
48 }
49
50 static void     release_memory(void)
51 {
52     memory_index = memory;
53 }
54
55 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
56
57 static char*    encodeA(const char* str)
58 {
59     size_t      len;
60     char*       ptr;
61     int         i;
62
63     if (!str) return "";
64     len = strlen(str) + 1;
65     ptr = grab_memory(len * 2 + 1);
66     for (i = 0; i < len; i++)
67         sprintf(&ptr[i * 2], "%02x", (unsigned char)str[i]);
68     ptr[2 * len] = '\0';
69     return ptr;
70 }
71
72 static char*    encodeW(const WCHAR* str)
73 {
74     size_t      len;
75     char*       ptr;
76     int         i;
77
78     if (!str) return "";
79     len = lstrlenW(str) + 1;
80     ptr = grab_memory(len * 4 + 1);
81     assert(ptr);
82     for (i = 0; i < len; i++)
83         sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
84     ptr[4 * len] = '\0';
85     return ptr;
86 }
87
88 static unsigned decode_char(char c)
89 {
90     if (c >= '0' && c <= '9') return c - '0';
91     if (c >= 'a' && c <= 'f') return c - 'a' + 10;
92     assert(c >= 'A' && c <= 'F');
93     return c - 'A' + 10;
94 }
95
96 static char*    decodeA(const char* str)
97 {
98     size_t      len;
99     char*       ptr;
100     int         i;
101
102     len = strlen(str) / 2;
103     if (!len--) return NULL;
104     ptr = grab_memory(len + 1);
105     for (i = 0; i < len; i++)
106         ptr[i] = (decode_char(str[2 * i]) << 4) | decode_char(str[2 * i + 1]);
107     ptr[len] = '\0';
108     return ptr;
109 }
110
111 static WCHAR*   decodeW(const char* str)
112 {
113     size_t      len;
114     WCHAR*      ptr;
115     int         i;
116
117     len = strlen(str) / 4;
118     if (!len--) return NULL;
119     ptr = (WCHAR*)grab_memory(len * 2 + 1);
120     for (i = 0; i < len; i++)
121         ptr[i] = (decode_char(str[4 * i]) << 12) | 
122             (decode_char(str[4 * i + 1]) << 8) |
123             (decode_char(str[4 * i + 2]) << 4) |
124             (decode_char(str[4 * i + 3]) << 0);
125     ptr[len] = '\0';
126     return ptr;
127 }
128
129 /******************************************************************
130  *              init
131  *
132  * generates basic information like:
133  *      base:           absolute path to curr dir
134  *      selfname:       the way to reinvoke ourselves
135  */
136 static int     init(void)
137 {
138     myARGC = winetest_get_mainargs( &myARGV );
139     if (!GetCurrentDirectoryA(sizeof(base), base)) return 0;
140     strcpy(selfname, myARGV[0]);
141     return 1;
142 }
143
144 /******************************************************************
145  *              get_file_name
146  *
147  * generates an absolute file_name for temporary file
148  *
149  */
150 static void     get_file_name(char* buf)
151 {
152     char        path[MAX_PATH];
153
154     buf[0] = '\0';
155     GetTempPathA(sizeof(path), path);
156     GetTempFileNameA(path, "wt", 0, buf);
157 }
158
159 /******************************************************************
160  *              static void     childPrintf
161  *
162  */
163 static void     childPrintf(HANDLE h, const char* fmt, ...)
164 {
165     va_list     valist;
166     char        buffer[2048];
167     DWORD       w;
168
169     va_start(valist, fmt);
170     vsprintf(buffer, fmt, valist);
171     va_end(valist);
172     WriteFile(h, buffer, strlen(buffer), &w, NULL);
173 }
174
175
176 /******************************************************************
177  *              doChild
178  *
179  * output most of the information in the child process
180  */
181 static void     doChild(const char* file)
182 {
183     STARTUPINFOA        siA;
184     STARTUPINFOW        siW;
185     int                 i;
186     char*               ptrA;
187     WCHAR*              ptrW;
188     char                bufA[MAX_PATH];
189     WCHAR               bufW[MAX_PATH];
190     HANDLE              hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
191
192     if (hFile == INVALID_HANDLE_VALUE) return;
193
194     /* output of startup info (Ansi) */
195     GetStartupInfoA(&siA);
196     childPrintf(hFile, 
197                 "[StartupInfoA]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
198                 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
199                 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
200                 "dwFlags=%lu\nwShowWindow=%u\n"
201                 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
202                 siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle),
203                 siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize, 
204                 siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute, 
205                 siA.dwFlags, siA.wShowWindow, 
206                 (DWORD)siA.hStdInput, (DWORD)siA.hStdOutput, (DWORD)siA.hStdError);
207
208     /* since GetStartupInfoW is only implemented in win2k, 
209      * zero out before calling so we can notice the difference
210      */
211     memset(&siW, 0, sizeof(siW));
212     GetStartupInfoW(&siW);
213     childPrintf(hFile, 
214                 "[StartupInfoW]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
215                 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
216                 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
217                 "dwFlags=%lu\nwShowWindow=%u\n"
218                 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
219                 siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle),
220                 siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize, 
221                 siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute, 
222                 siW.dwFlags, siW.wShowWindow, 
223                 (DWORD)siW.hStdInput, (DWORD)siW.hStdOutput, (DWORD)siW.hStdError);
224
225     /* Arguments */
226     childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
227     for (i = 0; i < myARGC; i++)
228     {
229         childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
230     }
231     childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
232
233 #if 0
234     int                 argcW;
235     WCHAR**             argvW;
236
237     /* this is part of shell32... and should be tested there */
238     argvW = CommandLineToArgvW(GetCommandLineW(), &argcW);
239     for (i = 0; i < argcW; i++)
240     {
241         childPrintf(hFile, "argvW%d=%s\n", i, encodeW(argvW[i]));
242     }
243 #endif
244     childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
245
246     /* output of environment (Ansi) */
247     ptrA = GetEnvironmentStringsA();
248     if (ptrA)
249     {
250         childPrintf(hFile, "[EnvironmentA]\n");
251         i = 0;
252         while (*ptrA)
253         {
254             if (strlen(ptrA) < 128)
255             {
256                 childPrintf(hFile, "env%d=%s\n", i, encodeA(ptrA));
257                 i++;
258             }
259             ptrA += strlen(ptrA) + 1;
260         }
261         childPrintf(hFile, "\n");
262     }
263
264     /* output of environment (Unicode) */
265     ptrW = GetEnvironmentStringsW();
266     if (ptrW)
267     {
268         childPrintf(hFile, "[EnvironmentW]\n");
269         i = 0;
270         while (*ptrW)
271         {
272             if (lstrlenW(ptrW) < 128)
273             {
274                 childPrintf(hFile, "env%d=%s\n", i, encodeW(ptrW));
275                 i++;
276             }
277             ptrW += lstrlenW(ptrW) + 1;
278         }
279         childPrintf(hFile, "\n");
280     }
281
282     childPrintf(hFile, "[Misc]\n");
283     if (GetCurrentDirectoryA(sizeof(bufA), bufA))
284         childPrintf(hFile, "CurrDirA=%s\n", encodeA(bufA));
285     if (GetCurrentDirectoryW(sizeof(bufW) / sizeof(bufW[0]), bufW))
286         childPrintf(hFile, "CurrDirW=%s\n", encodeW(bufW));
287     childPrintf(hFile, "\n");
288     
289     CloseHandle(hFile);
290 }
291
292 static char* getChildString(const char* sect, const char* key)
293 {
294     char        buf[1024];
295     char*       ret;
296
297     GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile);
298     if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL;
299     assert(!(strlen(buf) & 1));
300     ret = decodeA(buf);
301     return ret;
302 }
303
304 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
305  * others... (windows uses stricmp while Un*x uses strcasecmp...)
306  */
307 static int wtstrcasecmp(const char* p1, const char* p2)
308 {
309     char c1, c2;
310
311     c1 = c2 = '@';
312     while (c1 == c2 && c1)
313     {
314         c1 = *p1++; c2 = *p2++;
315         if (c1 != c2)
316         {
317             c1 = toupper(c1); c2 = toupper(c2);
318         }
319     }
320     return c1 - c2;
321 }
322
323 static int strCmp(const char* s1, const char* s2, BOOL sensitive)
324 {
325     if (!s1 && !s2) return 0;
326     if (!s2) return -1;
327     if (!s1) return 1;
328     return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2);
329 }
330
331 #define okChildString(sect, key, expect) \
332     do { \
333         char* result = getChildString(sect, key); \
334         ok(strCmp(result, expect, 1) == 0, "%s:%s expected %s, got %s", sect, key, expect, result); \
335     } while (0)
336
337 #define okChildIString(sect, key, expect) \
338     do { \
339         char* result = getChildString(sect, key); \
340         ok(strCmp(result, expect, 0) == 0, "%s:%s expected %s, got %s", sect, key, expect, result); \
341     } while (0)
342
343 /* using !expect insures that the test will fail if the sect/key isn't present
344  * in result file 
345  */
346 #define okChildInt(sect, key, expect) \
347     do { \
348         int result = GetPrivateProfileIntA(sect, key, !expect, resfile); \
349         ok(result == expect, "%s:%s expected %d, but got %d\n", sect, key, expect, result); \
350    } while (0)
351
352 static void test_Startup(void)
353 {
354     char                buffer[MAX_PATH];
355     PROCESS_INFORMATION info;
356     STARTUPINFOA        startup;
357
358     /* let's start simplistic */
359     memset(&startup, 0, sizeof(startup));
360     startup.cb = sizeof(startup);
361     startup.dwFlags = STARTF_USESHOWWINDOW;
362     startup.wShowWindow = SW_SHOWNORMAL;
363
364     get_file_name(resfile);
365     sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
366     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
367     /* wait for child to terminate */
368     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
369     /* child process has changed result file, so let profile functions know about it */
370     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
371
372     okChildInt("StartupInfoA", "cb", startup.cb);
373     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
374     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
375     okChildInt("StartupInfoA", "dwX", startup.dwX);
376     okChildInt("StartupInfoA", "dwY", startup.dwY);
377     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
378     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
379     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
380     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
381     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
382     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
383     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
384     release_memory();
385     assert(DeleteFileA(resfile) != 0);
386
387     /* not so simplistic now */
388     memset(&startup, 0, sizeof(startup));
389     startup.cb = sizeof(startup);
390     startup.dwFlags = STARTF_USESHOWWINDOW;
391     startup.wShowWindow = SW_SHOWNORMAL;
392     startup.lpTitle = "I'm the title string";
393     startup.lpDesktop = "I'm the desktop string";
394     startup.dwXCountChars = 0x12121212;
395     startup.dwYCountChars = 0x23232323;
396     startup.dwX = 0x34343434;
397     startup.dwY = 0x45454545;
398     startup.dwXSize = 0x56565656;
399     startup.dwYSize = 0x67676767;
400     startup.dwFillAttribute = 0xA55A;
401
402     get_file_name(resfile);
403     sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
404     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
405     /* wait for child to terminate */
406     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
407     /* child process has changed result file, so let profile functions know about it */
408     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
409
410     okChildInt("StartupInfoA", "cb", startup.cb);
411     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
412     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
413     okChildInt("StartupInfoA", "dwX", startup.dwX);
414     okChildInt("StartupInfoA", "dwY", startup.dwY);
415     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
416     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
417     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
418     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
419     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
420     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
421     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
422     release_memory();
423     assert(DeleteFileA(resfile) != 0);
424
425     /* not so simplistic now */
426     memset(&startup, 0, sizeof(startup));
427     startup.cb = sizeof(startup);
428     startup.dwFlags = STARTF_USESHOWWINDOW;
429     startup.wShowWindow = SW_SHOWNORMAL;
430     startup.lpTitle = "I'm the title string";
431     startup.lpDesktop = NULL;
432     startup.dwXCountChars = 0x12121212;
433     startup.dwYCountChars = 0x23232323;
434     startup.dwX = 0x34343434;
435     startup.dwY = 0x45454545;
436     startup.dwXSize = 0x56565656;
437     startup.dwYSize = 0x67676767;
438     startup.dwFillAttribute = 0xA55A;
439
440     get_file_name(resfile);
441     sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
442     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
443     /* wait for child to terminate */
444     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
445     /* child process has changed result file, so let profile functions know about it */
446     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
447
448     okChildInt("StartupInfoA", "cb", startup.cb);
449     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
450     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
451     okChildInt("StartupInfoA", "dwX", startup.dwX);
452     okChildInt("StartupInfoA", "dwY", startup.dwY);
453     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
454     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
455     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
456     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
457     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
458     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
459     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
460     release_memory();
461     assert(DeleteFileA(resfile) != 0);
462
463     /* not so simplistic now */
464     memset(&startup, 0, sizeof(startup));
465     startup.cb = sizeof(startup);
466     startup.dwFlags = STARTF_USESHOWWINDOW;
467     startup.wShowWindow = SW_SHOWNORMAL;
468     startup.lpTitle = "I'm the title string";
469     startup.lpDesktop = "";
470     startup.dwXCountChars = 0x12121212;
471     startup.dwYCountChars = 0x23232323;
472     startup.dwX = 0x34343434;
473     startup.dwY = 0x45454545;
474     startup.dwXSize = 0x56565656;
475     startup.dwYSize = 0x67676767;
476     startup.dwFillAttribute = 0xA55A;
477
478     get_file_name(resfile);
479     sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
480     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
481     /* wait for child to terminate */
482     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
483     /* child process has changed result file, so let profile functions know about it */
484     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
485
486     okChildInt("StartupInfoA", "cb", startup.cb);
487     todo_wine okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
488     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
489     okChildInt("StartupInfoA", "dwX", startup.dwX);
490     okChildInt("StartupInfoA", "dwY", startup.dwY);
491     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
492     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
493     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
494     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
495     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
496     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
497     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
498     release_memory();
499     assert(DeleteFileA(resfile) != 0);
500
501     /* not so simplistic now */
502     memset(&startup, 0, sizeof(startup));
503     startup.cb = sizeof(startup);
504     startup.dwFlags = STARTF_USESHOWWINDOW;
505     startup.wShowWindow = SW_SHOWNORMAL;
506     startup.lpTitle = NULL;
507     startup.lpDesktop = "I'm the desktop string";
508     startup.dwXCountChars = 0x12121212;
509     startup.dwYCountChars = 0x23232323;
510     startup.dwX = 0x34343434;
511     startup.dwY = 0x45454545;
512     startup.dwXSize = 0x56565656;
513     startup.dwYSize = 0x67676767;
514     startup.dwFillAttribute = 0xA55A;
515
516     get_file_name(resfile);
517     sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
518     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
519     /* wait for child to terminate */
520     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
521     /* child process has changed result file, so let profile functions know about it */
522     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
523
524     okChildInt("StartupInfoA", "cb", startup.cb);
525     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
526     okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
527     okChildInt("StartupInfoA", "dwX", startup.dwX);
528     okChildInt("StartupInfoA", "dwY", startup.dwY);
529     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
530     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
531     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
532     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
533     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
534     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
535     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
536     release_memory();
537     assert(DeleteFileA(resfile) != 0);
538
539     /* not so simplistic now */
540     memset(&startup, 0, sizeof(startup));
541     startup.cb = sizeof(startup);
542     startup.dwFlags = STARTF_USESHOWWINDOW;
543     startup.wShowWindow = SW_SHOWNORMAL;
544     startup.lpTitle = "";
545     startup.lpDesktop = "I'm the desktop string";
546     startup.dwXCountChars = 0x12121212;
547     startup.dwYCountChars = 0x23232323;
548     startup.dwX = 0x34343434;
549     startup.dwY = 0x45454545;
550     startup.dwXSize = 0x56565656;
551     startup.dwYSize = 0x67676767;
552     startup.dwFillAttribute = 0xA55A;
553
554     get_file_name(resfile);
555     sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
556     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
557     /* wait for child to terminate */
558     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
559     /* child process has changed result file, so let profile functions know about it */
560     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
561
562     okChildInt("StartupInfoA", "cb", startup.cb);
563     okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
564     todo_wine okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
565     okChildInt("StartupInfoA", "dwX", startup.dwX);
566     okChildInt("StartupInfoA", "dwY", startup.dwY);
567     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
568     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
569     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
570     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
571     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
572     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
573     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
574     release_memory();
575     assert(DeleteFileA(resfile) != 0);
576
577     /* not so simplistic now */
578     memset(&startup, 0, sizeof(startup));
579     startup.cb = sizeof(startup);
580     startup.dwFlags = STARTF_USESHOWWINDOW;
581     startup.wShowWindow = SW_SHOWNORMAL;
582     startup.lpTitle = "";
583     startup.lpDesktop = "";
584     startup.dwXCountChars = 0x12121212;
585     startup.dwYCountChars = 0x23232323;
586     startup.dwX = 0x34343434;
587     startup.dwY = 0x45454545;
588     startup.dwXSize = 0x56565656;
589     startup.dwYSize = 0x67676767;
590     startup.dwFillAttribute = 0xA55A;
591
592     get_file_name(resfile);
593     sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
594     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
595     /* wait for child to terminate */
596     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
597     /* child process has changed result file, so let profile functions know about it */
598     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
599
600     okChildInt("StartupInfoA", "cb", startup.cb);
601     todo_wine okChildString("StartupInfoA", "lpDesktop", startup.lpDesktop);
602     todo_wine okChildString("StartupInfoA", "lpTitle", startup.lpTitle);
603     okChildInt("StartupInfoA", "dwX", startup.dwX);
604     okChildInt("StartupInfoA", "dwY", startup.dwY);
605     okChildInt("StartupInfoA", "dwXSize", startup.dwXSize);
606     okChildInt("StartupInfoA", "dwYSize", startup.dwYSize);
607     okChildInt("StartupInfoA", "dwXCountChars", startup.dwXCountChars);
608     okChildInt("StartupInfoA", "dwYCountChars", startup.dwYCountChars);
609     okChildInt("StartupInfoA", "dwFillAttribute", startup.dwFillAttribute);
610     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
611     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
612     release_memory();
613     assert(DeleteFileA(resfile) != 0);
614
615     /* TODO: test for A/W and W/A and W/W */
616 }
617
618 static void test_CommandLine(void)
619 {
620     char                buffer[MAX_PATH];
621     PROCESS_INFORMATION info;
622     STARTUPINFOA        startup;
623
624     memset(&startup, 0, sizeof(startup));
625     startup.cb = sizeof(startup);
626     startup.dwFlags = STARTF_USESHOWWINDOW;
627     startup.wShowWindow = SW_SHOWNORMAL;
628
629     /* the basics */
630     get_file_name(resfile);
631     sprintf(buffer, "%s tests/process.c %s \"C:\\Program Files\\my nice app.exe\"", selfname, resfile);
632     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
633     /* wait for child to terminate */
634     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
635     /* child process has changed result file, so let profile functions know about it */
636     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
637
638     okChildInt("Arguments", "argcA", 4);
639     okChildString("Arguments", "argvA3", "C:\\Program Files\\my nice app.exe");
640     okChildString("Arguments", "argvA4", NULL);
641     okChildString("Arguments", "CommandLineA", buffer);
642     release_memory();
643     assert(DeleteFileA(resfile) != 0);
644
645     memset(&startup, 0, sizeof(startup));
646     startup.cb = sizeof(startup);
647     startup.dwFlags = STARTF_USESHOWWINDOW;
648     startup.wShowWindow = SW_SHOWNORMAL;
649
650     /* from Frangois */
651     get_file_name(resfile);
652     sprintf(buffer, "%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
653     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess");
654     /* wait for child to terminate */
655     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
656     /* child process has changed result file, so let profile functions know about it */
657     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
658
659     okChildInt("Arguments", "argcA", 6);
660     okChildString("Arguments", "argvA3", "a\"b\\");
661     okChildString("Arguments", "argvA4", "c\"");
662     okChildString("Arguments", "argvA5", "d");
663     okChildString("Arguments", "argvA6", NULL);
664     okChildString("Arguments", "CommandLineA", buffer);
665     release_memory();
666     assert(DeleteFileA(resfile) != 0);
667 }
668
669 static void test_Directory(void)
670 {
671     char                buffer[MAX_PATH];
672     PROCESS_INFORMATION info;
673     STARTUPINFOA        startup;
674     char windir[MAX_PATH];
675
676     memset(&startup, 0, sizeof(startup));
677     startup.cb = sizeof(startup);
678     startup.dwFlags = STARTF_USESHOWWINDOW;
679     startup.wShowWindow = SW_SHOWNORMAL;
680
681     /* the basics */
682     get_file_name(resfile);
683     sprintf(buffer, "%s tests/process.c %s", selfname, resfile);
684     GetWindowsDirectoryA( windir, sizeof(windir) );
685     ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, windir, &startup, &info), "CreateProcess");
686     /* wait for child to terminate */
687     ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination");
688     /* child process has changed result file, so let profile functions know about it */
689     WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
690
691     okChildIString("Misc", "CurrDirA", windir);
692     release_memory();
693     assert(DeleteFileA(resfile) != 0);
694 }
695
696 START_TEST(process)
697 {
698     int b = init();
699     ok(b, "Basic init of CreateProcess test");
700     if (!b) return;
701
702     if (myARGC >= 3)
703     {
704         doChild(myARGV[2]);
705         return;
706     }
707     test_Startup();
708     test_CommandLine();
709     test_Directory();
710
711     /* things that can be tested:
712      *  lookup:         check the way program to be executed is searched
713      *  environment:    check environment string passing
714      *  handles:        check the handle inheritance stuff (+sec options)
715      *  console:        check if console creation parameters work
716      */
717 }