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