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