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