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