2 * Unit test suite for process functions
4 * Copyright 2002 Eric Pouech
5 * Copyright 2006 Dmitry Timoshkov
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.
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.
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
28 #define WIN32_NO_STATUS
36 #include "wine/test.h"
38 #define expect_eq_d(expected, actual) \
40 int value = (actual); \
41 ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \
44 #define expect_eq_s(expected, actual) \
46 LPCSTR value = (actual); \
47 ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \
50 #define expect_eq_ws_i(expected, actual) \
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)); \
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);
67 /* ############################### */
68 static char base[MAX_PATH];
69 static char selfname[MAX_PATH];
71 static char resfile[MAX_PATH];
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).
81 #define MAX_LISTED_ENV_VAR 128
83 /* ---------------- portable memory allocation thingie */
85 static char memory[1024*256];
86 static char* memory_index = memory;
88 static char* grab_memory(size_t len)
90 char* ret = memory_index;
94 assert(memory_index <= memory + sizeof(memory));
98 static void release_memory(void)
100 memory_index = memory;
103 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
105 static const char* encodeA(const char* str)
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]);
119 static const char* encodeW(const WCHAR* str)
125 len = lstrlenW(str) + 1;
126 ptr = grab_memory(len * 4 + 1);
128 for (i = 0; i < len; i++)
129 sprintf(&ptr[i * 4], "%04x", (unsigned int)(unsigned short)str[i]);
134 static unsigned decode_char(char c)
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');
142 static char* decodeA(const char* str)
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]);
156 /* This will be needed to decode Unicode strings saved by the child process
157 * when we test Unicode functions.
159 static WCHAR* decodeW(const char* str)
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);
177 /******************************************************************
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
186 static int init(void)
190 myARGC = winetest_get_mainargs( &myARGV );
191 if (!GetCurrentDirectoryA(sizeof(base), base)) return 0;
192 strcpy(selfname, myARGV[0]);
194 /* Strip the path of selfname */
195 if ((p = strrchr(selfname, '\\')) != NULL) exename = p + 1;
196 else exename = selfname;
198 if ((p = strrchr(exename, '/')) != NULL) exename = p + 1;
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");
212 /******************************************************************
215 * generates an absolute file_name for temporary file
218 static void get_file_name(char* buf)
223 GetTempPathA(sizeof(path), path);
224 GetTempFileNameA(path, "wt", 0, buf);
227 /******************************************************************
228 * static void childPrintf
231 static void childPrintf(HANDLE h, const char* fmt, ...)
234 char buffer[1024+4*MAX_LISTED_ENV_VAR];
237 va_start(valist, fmt);
238 vsprintf(buffer, fmt, valist);
240 WriteFile(h, buffer, strlen(buffer), &w, NULL);
244 /******************************************************************
247 * output most of the information in the child process
249 static void doChild(const char* file, const char* option)
254 char *ptrA, *ptrA_save;
255 WCHAR *ptrW, *ptrW_save;
257 WCHAR bufW[MAX_PATH];
258 HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
261 if (hFile == INVALID_HANDLE_VALUE) return;
263 /* output of startup info (Ansi) */
264 GetStartupInfoA(&siA);
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);
277 /* since GetStartupInfoW is only implemented in win2k,
278 * zero out before calling so we can notice the difference
280 memset(&siW, 0, sizeof(siW));
281 GetStartupInfoW(&siW);
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);
295 childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC);
296 for (i = 0; i < myARGC; i++)
298 childPrintf(hFile, "argvA%d=%s\n", i, encodeA(myARGV[i]));
300 childPrintf(hFile, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
301 childPrintf(hFile, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
303 /* output of environment (Ansi) */
304 ptrA_save = ptrA = GetEnvironmentStringsA();
307 char env_var[MAX_LISTED_ENV_VAR];
309 childPrintf(hFile, "[EnvironmentA]\n");
313 lstrcpynA(env_var, ptrA, MAX_LISTED_ENV_VAR);
314 childPrintf(hFile, "env%d=%s\n", i, encodeA(env_var));
316 ptrA += strlen(ptrA) + 1;
318 childPrintf(hFile, "len=%d\n\n", i);
319 FreeEnvironmentStringsA(ptrA_save);
322 /* output of environment (Unicode) */
323 ptrW_save = ptrW = GetEnvironmentStringsW();
326 WCHAR env_var[MAX_LISTED_ENV_VAR];
328 childPrintf(hFile, "[EnvironmentW]\n");
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));
336 ptrW += lstrlenW(ptrW) + 1;
338 childPrintf(hFile, "len=%d\n\n", i);
339 FreeEnvironmentStringsW(ptrW_save);
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");
349 if (option && strcmp(option, "console") == 0)
351 CONSOLE_SCREEN_BUFFER_INFO sbi;
352 HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE);
353 HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
354 DWORD modeIn, modeOut;
356 childPrintf(hFile, "[Console]\n");
357 if (GetConsoleScreenBufferInfo(hConOut, &sbi))
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);
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);
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)
378 win_skip("Setting the codepage is not implemented\n");
382 ok(ret, "Setting CP\n");
383 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
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());
395 if (option && strcmp(option, "stdhandle") == 0)
397 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
398 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
400 if (hStdIn != INVALID_HANDLE_VALUE || hStdOut != INVALID_HANDLE_VALUE)
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");
411 if (option && strcmp(option, "exit_code") == 0)
413 childPrintf(hFile, "[ExitCode]\nvalue=%d\n\n", 123);
421 static char* getChildString(const char* sect, const char* key)
423 char buf[1024+4*MAX_LISTED_ENV_VAR];
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));
433 static WCHAR* getChildStringW(const char* sect, const char* key)
435 char buf[1024+4*MAX_LISTED_ENV_VAR];
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));
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...)
448 static int wtstrcasecmp(const char* p1, const char* p2)
453 while (c1 == c2 && c1)
455 c1 = *p1++; c2 = *p2++;
458 c1 = toupper(c1); c2 = toupper(c2);
464 static int strCmp(const char* s1, const char* s2, BOOL sensitive)
466 if (!s1 && !s2) return 0;
469 return (sensitive) ? strcmp(s1, s2) : wtstrcasecmp(s1, s2);
472 static void ok_child_string( int line, const char *sect, const char *key,
473 const char *expect, int sensitive )
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 );
480 static void ok_child_stringWA( int line, const char *sect, const char *key,
481 const char *expect, int sensitive )
486 WCHAR* result = getChildStringW( sect, key );
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);
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);
497 ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n",
498 sect, key, expect ? expect : "(null)", resultA );
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);
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 )
510 /* using !expect ensures that the test will fail if the sect/key isn't present
513 #define okChildInt(sect, key, expect) \
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); \
519 static void test_Startup(void)
521 char buffer[MAX_PATH];
522 PROCESS_INFORMATION info;
523 STARTUPINFOA startup,si;
525 static CHAR title[] = "I'm the title string",
526 desktop[] = "winsta0\\default",
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;
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);
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);
556 assert(DeleteFileA(resfile) != 0);
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;
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);
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);
594 assert(DeleteFileA(resfile) != 0);
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;
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);
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);
632 assert(DeleteFileA(resfile) != 0);
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;
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);
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);
670 assert(DeleteFileA(resfile) != 0);
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;
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);
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);
710 assert(DeleteFileA(resfile) != 0);
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;
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);
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);
748 assert(DeleteFileA(resfile) != 0);
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;
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);
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);
786 assert(DeleteFileA(resfile) != 0);
788 /* TODO: test for A/W and W/A and W/W */
791 static void test_CommandLine(void)
793 char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
794 char buffer2[MAX_PATH];
795 PROCESS_INFORMATION info;
796 STARTUPINFOA startup;
799 memset(&startup, 0, sizeof(startup));
800 startup.cb = sizeof(startup);
801 startup.dwFlags = STARTF_USESHOWWINDOW;
802 startup.wShowWindow = SW_SHOWNORMAL;
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);
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);
818 assert(DeleteFileA(resfile) != 0);
820 memset(&startup, 0, sizeof(startup));
821 startup.cb = sizeof(startup);
822 startup.dwFlags = STARTF_USESHOWWINDOW;
823 startup.wShowWindow = SW_SHOWNORMAL;
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);
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);
841 assert(DeleteFileA(resfile) != 0);
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);
857 assert(DeleteFileA(resfile) != 0);
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);
872 assert(DeleteFileA(resfile) != 0);
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);
893 assert(DeleteFileA(resfile) != 0);
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);
917 assert(DeleteFileA(resfile) != 0);
919 if (0) /* Test crashes on NT-based Windows. */
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());
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());
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());
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());
961 strcpy(buffer, "doesnotexist.exe");
962 strcpy(buffer2, "does not exist.exe");
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());
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());
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());
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());
987 static void test_Directory(void)
989 char buffer[MAX_PATH];
990 PROCESS_INFORMATION info;
991 STARTUPINFOA startup;
992 char windir[MAX_PATH];
993 static CHAR cmdline[] = "winver.exe";
995 memset(&startup, 0, sizeof(startup));
996 startup.cb = sizeof(startup);
997 startup.dwFlags = STARTF_USESHOWWINDOW;
998 startup.wShowWindow = SW_SHOWNORMAL;
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);
1010 okChildIString("Misc", "CurrDirA", windir);
1012 assert(DeleteFileA(resfile) != 0);
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");
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");
1027 static BOOL is_str_env_drive_dir(const char* str)
1029 return str[0] == '=' && str[1] >= 'A' && str[1] <= 'Z' && str[2] == ':' &&
1030 str[3] == '=' && str[4] == str[1];
1033 /* compared expected child's environment (in gesA) from actual
1034 * environment our child got
1036 static void cmpEnvironment(const char* gesA)
1044 clen = GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile);
1046 /* now look each parent env in child */
1047 if ((ptrA = gesA) != NULL)
1051 for (i = 0; i < clen; i++)
1053 sprintf(key, "env%d", i);
1054 res = getChildString("EnvironmentA", key);
1055 if (strncmp(ptrA, res, MAX_LISTED_ENV_VAR - 1) == 0)
1059 ok(found, "Parent-env string %s isn't in child process\n", ptrA);
1061 ptrA += strlen(ptrA) + 1;
1065 /* and each child env in parent */
1066 for (i = 0; i < clen; i++)
1068 sprintf(key, "env%d", i);
1069 res = getChildString("EnvironmentA", key);
1070 if ((ptrA = gesA) != NULL)
1074 if (strncmp(res, ptrA, MAX_LISTED_ENV_VAR - 1) == 0)
1076 ptrA += strlen(ptrA) + 1;
1078 if (!*ptrA) ptrA = NULL;
1081 if (!is_str_env_drive_dir(res))
1083 found = ptrA != NULL;
1084 ok(found, "Child-env string %s isn't in parent process\n", res);
1086 /* else => should also test we get the right per drive default directory here... */
1090 static void test_Environment(void)
1092 char buffer[MAX_PATH];
1093 PROCESS_INFORMATION info;
1094 STARTUPINFOA startup;
1102 memset(&startup, 0, sizeof(startup));
1103 startup.cb = sizeof(startup);
1104 startup.dwFlags = STARTF_USESHOWWINDOW;
1105 startup.wShowWindow = SW_SHOWNORMAL;
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);
1116 env = GetEnvironmentStringsA();
1117 cmpEnvironment(env);
1119 assert(DeleteFileA(resfile) != 0);
1121 memset(&startup, 0, sizeof(startup));
1122 startup.cb = sizeof(startup);
1123 startup.dwFlags = STARTF_USESHOWWINDOW;
1124 startup.wShowWindow = SW_SHOWNORMAL;
1127 get_file_name(resfile);
1128 sprintf(buffer, "\"%s\" tests/process.c \"%s\"", selfname, resfile);
1134 slen = strlen(ptr)+1;
1135 child_env_len += slen;
1138 /* Add space for additional environment variables */
1139 child_env_len += 256;
1140 child_env = HeapAlloc(GetProcessHeap(), 0, child_env_len);
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:
1153 * - PATH (already set above)
1154 * - the directory definitions (=[A-Z]:=)
1156 for (ptr2 = env; *ptr2; ptr2 += strlen(ptr2) + 1)
1158 if (strncmp(ptr2, "PATH=", 5) != 0 &&
1159 strncmp(ptr2, "WINELOADER=", 11) != 0 &&
1160 !is_str_env_drive_dir(ptr2))
1163 ptr += strlen(ptr) + 1;
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);
1173 cmpEnvironment(child_env);
1175 HeapFree(GetProcessHeap(), 0, child_env);
1176 FreeEnvironmentStringsA(env);
1178 assert(DeleteFileA(resfile) != 0);
1181 static void test_SuspendFlag(void)
1183 char buffer[MAX_PATH];
1184 PROCESS_INFORMATION info;
1185 STARTUPINFOA startup, us;
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;
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");
1199 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1201 ok(GetExitCodeThread(info.hThread, &exit_status) && exit_status == STILL_ACTIVE, "thread still running\n");
1202 ok(ResumeThread(info.hThread) == 1, "Resuming thread\n");
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);
1209 GetStartupInfoA(&us);
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);
1226 assert(DeleteFileA(resfile) != 0);
1229 static void test_DebuggingFlag(void)
1231 char buffer[MAX_PATH];
1232 void *processbase = NULL;
1233 PROCESS_INFORMATION info;
1234 STARTUPINFOA startup, us;
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;
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");
1249 /* get all startup events up to the entry point break exception */
1252 ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
1253 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
1256 ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT,
1257 "first event: %d\n", de.dwDebugEventCode);
1258 processbase = de.u.CreateProcessInfo.lpBaseOfImage;
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);
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);
1271 GetStartupInfoA(&us);
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);
1288 assert(DeleteFileA(resfile) != 0);
1291 static BOOL is_console(HANDLE h)
1293 return h != INVALID_HANDLE_VALUE && ((ULONG_PTR)h & 3) == 3;
1296 static void test_Console(void)
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;
1306 HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut;
1307 const char* msg = "This is a std-handle inheritance test.";
1309 BOOL run_tests = TRUE;
1312 memset(&startup, 0, sizeof(startup));
1313 startup.cb = sizeof(startup);
1314 startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
1315 startup.wShowWindow = SW_SHOWNORMAL;
1317 sa.nLength = sizeof(sa);
1318 sa.lpSecurityDescriptor = NULL;
1319 sa.bInheritHandle = TRUE;
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);
1324 /* first, we need to be sure we're attached to a console */
1325 if (!is_console(startup.hStdInput) || !is_console(startup.hStdOutput))
1327 /* we're not attached to a console, let's do it */
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);
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;
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();
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");
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);
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");
1357 SetConsoleMode(startup.hStdInput, modeIn);
1358 SetConsoleMode(startup.hStdOutput, modeOut);
1360 cpInC = GetConsoleCP();
1361 cpOutC = GetConsoleOutputCP();
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)
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());
1382 SetConsoleOutputCP(cpOut);
1384 GetStartupInfoA(&us);
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);
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);
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);
1427 win_skip("Setting the codepage is not implemented\n");
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");
1435 assert(DeleteFileA(resfile) != 0);
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);
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);
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;
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");
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);
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);
1475 okChildString("StdHandle", "msg", msg);
1478 assert(DeleteFileA(resfile) != 0);
1481 static void test_ExitCode(void)
1483 char buffer[MAX_PATH];
1484 PROCESS_INFORMATION info;
1485 STARTUPINFOA startup;
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;
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");
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);
1503 ok(GetExitCodeProcess(info.hProcess, &code), "Getting exit code\n");
1504 okChildInt("ExitCode", "value", code);
1507 assert(DeleteFileA(resfile) != 0);
1510 static void test_OpenProcess(void)
1514 MEMORY_BASIC_INFORMATION info;
1515 SIZE_T dummy, read_bytes;
1518 /* not exported in all windows versions */
1519 if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
1520 win_skip("VirtualAllocEx not found\n");
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());
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)
1534 win_skip("VirtualAllocEx not implemented\n");
1537 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
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);
1547 hproc = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId());
1548 ok(hproc != NULL, "OpenProcess error %d\n", GetLastError());
1550 addr1 = pVirtualAllocEx(hproc, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
1551 ok(addr1 != NULL, "VirtualAllocEx error %d\n", GetLastError());
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());
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);
1569 hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
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());
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);
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());
1593 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
1596 static void test_GetProcessVersion(void)
1598 static char cmdline[] = "winver.exe";
1599 PROCESS_INFORMATION pi;
1603 SetLastError(0xdeadbeef);
1604 ret = GetProcessVersion(0);
1605 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1607 SetLastError(0xdeadbeef);
1608 ret = GetProcessVersion(GetCurrentProcessId());
1609 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1611 memset(&si, 0, sizeof(si));
1613 si.dwFlags = STARTF_USESHOWWINDOW;
1614 si.wShowWindow = SW_HIDE;
1615 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1616 SetLastError(0xdeadbeef);
1617 ok(ret, "CreateProcess error %u\n", GetLastError());
1619 SetLastError(0xdeadbeef);
1620 ret = GetProcessVersion(pi.dwProcessId);
1621 ok(ret, "GetProcessVersion error %u\n", GetLastError());
1623 SetLastError(0xdeadbeef);
1624 ret = TerminateProcess(pi.hProcess, 0);
1625 ok(ret, "TerminateProcess error %u\n", GetLastError());
1627 CloseHandle(pi.hProcess);
1628 CloseHandle(pi.hThread);
1631 static void test_GetProcessImageFileNameA(void)
1634 CHAR process[MAX_PATH];
1635 static const char harddisk[] = "\\Device\\HarddiskVolume";
1637 if (!pK32GetProcessImageFileNameA)
1639 win_skip("K32GetProcessImageFileNameA is unavailable\n");
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());
1650 rc = pK32GetProcessImageFileNameA(GetCurrentProcess(), process, sizeof(process));
1651 expect_eq_d(rc, lstrlenA(process));
1652 if (strncmp(process, harddisk, lstrlenA(harddisk)))
1654 todo_wine win_skip("%s is probably on a network share, skipping tests\n", process);
1658 if (!pQueryFullProcessImageNameA)
1659 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
1662 CHAR image[MAX_PATH];
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);
1672 static void test_QueryFullProcessImageNameA(void)
1674 #define INIT_STR "Just some words"
1676 CHAR buf[MAX_PATH], module[MAX_PATH];
1678 if (!pQueryFullProcessImageNameA)
1680 win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n");
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());
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);
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
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);
1708 /* retest with smaller buffer size
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);
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
1722 expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size));
1723 expect_eq_d(1024, size);
1724 expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError());
1727 static void test_QueryFullProcessImageNameW(void)
1730 WCHAR module_name[1024], device[1024];
1731 WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0};
1735 if (!pQueryFullProcessImageNameW)
1737 win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n");
1741 ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n");
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);
1749 hSelf = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
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);
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 */
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());
1774 expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size));
1775 expect_eq_d(0, size);
1776 expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError());
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 */
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");
1795 module_name[2] = '\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));
1802 if (size >= lstrlenW(buf))
1804 ok(0, "expected %s\\ to match the start of %s\n", wine_dbgstr_w(device), wine_dbgstr_w(buf));
1808 ok(buf[len] == '\\', "expected '%c' to be a '\\' in %s\n", buf[len], wine_dbgstr_w(module_name));
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));
1817 static void test_Handles(void)
1819 HANDLE handle = GetCurrentProcess();
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() );
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() );
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 );
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 );
1863 static void test_SystemInfo(void)
1865 SYSTEM_INFO si, nsi;
1868 if (!pGetNativeSystemInfo)
1870 win_skip("GetNativeSystemInfo is not available\n");
1874 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1877 pGetNativeSystemInfo(&nsi);
1880 if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
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);
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);
1901 static void test_RegistryQuota(void)
1904 DWORD max_quota, used_quota;
1906 if (!pGetSystemRegistryQuota)
1908 win_skip("GetSystemRegistryQuota is not available\n");
1912 ret = pGetSystemRegistryQuota(NULL, NULL);
1914 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
1916 ret = pGetSystemRegistryQuota(&max_quota, NULL);
1918 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
1920 ret = pGetSystemRegistryQuota(NULL, &used_quota);
1922 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
1924 ret = pGetSystemRegistryQuota(&max_quota, &used_quota);
1926 "Expected GetSystemRegistryQuota to return TRUE, got %d\n", ret);
1932 ok(b, "Basic init of CreateProcess test\n");
1937 doChild(myARGV[2], (myARGC == 3) ? NULL : myARGV[3]);
1945 test_DebuggingFlag();
1949 test_GetProcessVersion();
1950 test_GetProcessImageFileNameA();
1951 test_QueryFullProcessImageNameA();
1952 test_QueryFullProcessImageNameW();
1955 test_RegistryQuota();
1956 /* things that can be tested:
1957 * lookup: check the way program to be executed is searched
1958 * handles: check the handle inheritance stuff (+sec options)
1959 * console: check if console creation parameters work