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