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