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