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