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