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