2 * Unit test suite for CreateProcess function.
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
27 #include "wine/test.h"
34 static HINSTANCE hkernel32
;
35 static LPVOID (WINAPI
*pVirtualAllocEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
, DWORD
);
36 static BOOL (WINAPI
*pVirtualFreeEx
)(HANDLE
, LPVOID
, SIZE_T
, DWORD
);
38 /* ############################### */
39 static char base
[MAX_PATH
];
40 static char selfname
[MAX_PATH
];
42 static char resfile
[MAX_PATH
];
47 /* As some environment variables get very long on Unix, we only test for
48 * the first 127 bytes.
49 * Note that increasing this value past 256 may exceed the buffer size
50 * limitations of the *Profile functions (at least on Wine).
52 #define MAX_LISTED_ENV_VAR 128
54 /* ---------------- portable memory allocation thingie */
56 static char memory
[1024*256];
57 static char* memory_index
= memory
;
59 static char* grab_memory(size_t len
)
61 char* ret
= memory_index
;
65 assert(memory_index
<= memory
+ sizeof(memory
));
69 static void release_memory(void)
71 memory_index
= memory
;
74 /* ---------------- simplistic tool to encode/decode strings (to hide \ " ' and such) */
76 static const char* encodeA(const char* str
)
82 len
= strlen(str
) + 1;
83 ptr
= grab_memory(len
* 2 + 1);
84 for (i
= 0; i
< len
; i
++)
85 sprintf(&ptr
[i
* 2], "%02x", (unsigned char)str
[i
]);
90 static const char* encodeW(const WCHAR
* str
)
96 len
= lstrlenW(str
) + 1;
97 ptr
= grab_memory(len
* 4 + 1);
99 for (i
= 0; i
< len
; i
++)
100 sprintf(&ptr
[i
* 4], "%04x", (unsigned int)(unsigned short)str
[i
]);
105 static unsigned decode_char(char c
)
107 if (c
>= '0' && c
<= '9') return c
- '0';
108 if (c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
109 assert(c
>= 'A' && c
<= 'F');
113 static char* decodeA(const char* str
)
118 len
= strlen(str
) / 2;
119 if (!len
--) return NULL
;
120 ptr
= grab_memory(len
+ 1);
121 for (i
= 0; i
< len
; i
++)
122 ptr
[i
] = (decode_char(str
[2 * i
]) << 4) | decode_char(str
[2 * i
+ 1]);
128 /* This will be needed to decode Unicode strings saved by the child process
129 * when we test Unicode functions.
131 static WCHAR
* decodeW(const char* str
)
137 len
= strlen(str
) / 4;
138 if (!len
--) return NULL
;
139 ptr
= (WCHAR
*)grab_memory(len
* 2 + 1);
140 for (i
= 0; i
< len
; i
++)
141 ptr
[i
] = (decode_char(str
[4 * i
]) << 12) |
142 (decode_char(str
[4 * i
+ 1]) << 8) |
143 (decode_char(str
[4 * i
+ 2]) << 4) |
144 (decode_char(str
[4 * i
+ 3]) << 0);
150 /******************************************************************
153 * generates basic information like:
154 * base: absolute path to curr dir
155 * selfname: the way to reinvoke ourselves
156 * exename: executable without the path
157 * function-pointers, which are not implemented in all windows versions
159 static int init(void)
163 myARGC
= winetest_get_mainargs( &myARGV
);
164 if (!GetCurrentDirectoryA(sizeof(base
), base
)) return 0;
165 strcpy(selfname
, myARGV
[0]);
167 /* Strip the path of selfname */
168 if ((p
= strrchr(selfname
, '\\')) != NULL
) exename
= p
+ 1;
169 else exename
= selfname
;
171 if ((p
= strrchr(exename
, '/')) != NULL
) exename
= p
+ 1;
173 hkernel32
= GetModuleHandleA("kernel32");
174 pVirtualAllocEx
= (void *) GetProcAddress(hkernel32
, "VirtualAllocEx");
175 pVirtualFreeEx
= (void *) GetProcAddress(hkernel32
, "VirtualFreeEx");
179 /******************************************************************
182 * generates an absolute file_name for temporary file
185 static void get_file_name(char* buf
)
190 GetTempPathA(sizeof(path
), path
);
191 GetTempFileNameA(path
, "wt", 0, buf
);
194 /******************************************************************
195 * static void childPrintf
198 static void childPrintf(HANDLE h
, const char* fmt
, ...)
201 char buffer
[1024+4*MAX_LISTED_ENV_VAR
];
204 va_start(valist
, fmt
);
205 vsprintf(buffer
, fmt
, valist
);
207 WriteFile(h
, buffer
, strlen(buffer
), &w
, NULL
);
211 /******************************************************************
214 * output most of the information in the child process
216 static void doChild(const char* file
, const char* option
)
224 WCHAR bufW
[MAX_PATH
];
225 HANDLE hFile
= CreateFileA(file
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
228 if (hFile
== INVALID_HANDLE_VALUE
) return;
230 /* output of startup info (Ansi) */
231 GetStartupInfoA(&siA
);
233 "[StartupInfoA]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
234 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
235 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
236 "dwFlags=%lu\nwShowWindow=%u\n"
237 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
238 siA
.cb
, encodeA(siA
.lpDesktop
), encodeA(siA
.lpTitle
),
239 siA
.dwX
, siA
.dwY
, siA
.dwXSize
, siA
.dwYSize
,
240 siA
.dwXCountChars
, siA
.dwYCountChars
, siA
.dwFillAttribute
,
241 siA
.dwFlags
, siA
.wShowWindow
,
242 (DWORD
)siA
.hStdInput
, (DWORD
)siA
.hStdOutput
, (DWORD
)siA
.hStdError
);
244 /* since GetStartupInfoW is only implemented in win2k,
245 * zero out before calling so we can notice the difference
247 memset(&siW
, 0, sizeof(siW
));
248 GetStartupInfoW(&siW
);
250 "[StartupInfoW]\ncb=%08ld\nlpDesktop=%s\nlpTitle=%s\n"
251 "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n"
252 "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n"
253 "dwFlags=%lu\nwShowWindow=%u\n"
254 "hStdInput=%lu\nhStdOutput=%lu\nhStdError=%lu\n\n",
255 siW
.cb
, encodeW(siW
.lpDesktop
), encodeW(siW
.lpTitle
),
256 siW
.dwX
, siW
.dwY
, siW
.dwXSize
, siW
.dwYSize
,
257 siW
.dwXCountChars
, siW
.dwYCountChars
, siW
.dwFillAttribute
,
258 siW
.dwFlags
, siW
.wShowWindow
,
259 (DWORD
)siW
.hStdInput
, (DWORD
)siW
.hStdOutput
, (DWORD
)siW
.hStdError
);
262 childPrintf(hFile
, "[Arguments]\nargcA=%d\n", myARGC
);
263 for (i
= 0; i
< myARGC
; i
++)
265 childPrintf(hFile
, "argvA%d=%s\n", i
, encodeA(myARGV
[i
]));
267 childPrintf(hFile
, "CommandLineA=%s\n", encodeA(GetCommandLineA()));
273 /* this is part of shell32... and should be tested there */
274 argvW
= CommandLineToArgvW(GetCommandLineW(), &argcW
);
275 for (i
= 0; i
< argcW
; i
++)
277 childPrintf(hFile
, "argvW%d=%s\n", i
, encodeW(argvW
[i
]));
280 childPrintf(hFile
, "CommandLineW=%s\n\n", encodeW(GetCommandLineW()));
282 /* output of environment (Ansi) */
283 ptrA
= GetEnvironmentStringsA();
286 char env_var
[MAX_LISTED_ENV_VAR
];
288 childPrintf(hFile
, "[EnvironmentA]\n");
292 lstrcpynA(env_var
, ptrA
, MAX_LISTED_ENV_VAR
);
293 childPrintf(hFile
, "env%d=%s\n", i
, encodeA(env_var
));
295 ptrA
+= strlen(ptrA
) + 1;
297 childPrintf(hFile
, "len=%d\n\n", i
);
300 /* output of environment (Unicode) */
301 ptrW
= GetEnvironmentStringsW();
304 WCHAR env_var
[MAX_LISTED_ENV_VAR
];
306 childPrintf(hFile
, "[EnvironmentW]\n");
310 lstrcpynW(env_var
, ptrW
, MAX_LISTED_ENV_VAR
- 1);
311 env_var
[MAX_LISTED_ENV_VAR
- 1] = '\0';
312 childPrintf(hFile
, "env%d=%s\n", i
, encodeW(env_var
));
314 ptrW
+= lstrlenW(ptrW
) + 1;
316 childPrintf(hFile
, "len=%d\n\n", i
);
319 childPrintf(hFile
, "[Misc]\n");
320 if (GetCurrentDirectoryA(sizeof(bufA
), bufA
))
321 childPrintf(hFile
, "CurrDirA=%s\n", encodeA(bufA
));
322 if (GetCurrentDirectoryW(sizeof(bufW
) / sizeof(bufW
[0]), bufW
))
323 childPrintf(hFile
, "CurrDirW=%s\n", encodeW(bufW
));
324 childPrintf(hFile
, "\n");
326 if (option
&& strcmp(option
, "console") == 0)
328 CONSOLE_SCREEN_BUFFER_INFO sbi
;
329 HANDLE hConIn
= GetStdHandle(STD_INPUT_HANDLE
);
330 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
331 DWORD modeIn
, modeOut
;
333 childPrintf(hFile
, "[Console]\n");
334 if (GetConsoleScreenBufferInfo(hConOut
, &sbi
))
336 childPrintf(hFile
, "SizeX=%d\nSizeY=%d\nCursorX=%d\nCursorY=%d\nAttributes=%d\n",
337 sbi
.dwSize
.X
, sbi
.dwSize
.Y
, sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
.Y
, sbi
.wAttributes
);
338 childPrintf(hFile
, "winLeft=%d\nwinTop=%d\nwinRight=%d\nwinBottom=%d\n",
339 sbi
.srWindow
.Left
, sbi
.srWindow
.Top
, sbi
.srWindow
.Right
, sbi
.srWindow
.Bottom
);
340 childPrintf(hFile
, "maxWinWidth=%d\nmaxWinHeight=%d\n",
341 sbi
.dwMaximumWindowSize
.X
, sbi
.dwMaximumWindowSize
.Y
);
343 childPrintf(hFile
, "InputCP=%d\nOutputCP=%d\n",
344 GetConsoleCP(), GetConsoleOutputCP());
345 if (GetConsoleMode(hConIn
, &modeIn
))
346 childPrintf(hFile
, "InputMode=%ld\n", modeIn
);
347 if (GetConsoleMode(hConOut
, &modeOut
))
348 childPrintf(hFile
, "OutputMode=%ld\n", modeOut
);
350 /* now that we have written all relevant information, let's change it */
351 ok(SetConsoleCP(1252), "Setting CP\n");
352 ok(SetConsoleOutputCP(1252), "Setting SB CP\n");
353 ret
= SetConsoleMode(hConIn
, modeIn
^ 1);
354 ok( ret
, "Setting mode (%d)\n", GetLastError());
355 ret
= SetConsoleMode(hConOut
, modeOut
^ 1);
356 ok( ret
, "Setting mode (%d)\n", GetLastError());
357 sbi
.dwCursorPosition
.X
^= 1;
358 sbi
.dwCursorPosition
.Y
^= 1;
359 ret
= SetConsoleCursorPosition(hConOut
, sbi
.dwCursorPosition
);
360 ok( ret
, "Setting cursor position (%d)\n", GetLastError());
362 if (option
&& strcmp(option
, "stdhandle") == 0)
364 HANDLE hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
365 HANDLE hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
367 if (hStdIn
!= INVALID_HANDLE_VALUE
|| hStdOut
!= INVALID_HANDLE_VALUE
)
372 ok(ReadFile(hStdIn
, buf
, sizeof(buf
), &r
, NULL
) && r
> 0, "Reading message from input pipe\n");
373 childPrintf(hFile
, "[StdHandle]\nmsg=%s\n\n", encodeA(buf
));
374 ok(WriteFile(hStdOut
, buf
, r
, &w
, NULL
) && w
== r
, "Writing message to output pipe\n");
378 if (option
&& strcmp(option
, "exit_code") == 0)
380 childPrintf(hFile
, "[ExitCode]\nvalue=%d\n\n", 123);
388 static char* getChildString(const char* sect
, const char* key
)
390 char buf
[1024+4*MAX_LISTED_ENV_VAR
];
393 GetPrivateProfileStringA(sect
, key
, "-", buf
, sizeof(buf
), resfile
);
394 if (buf
[0] == '\0' || (buf
[0] == '-' && buf
[1] == '\0')) return NULL
;
395 assert(!(strlen(buf
) & 1));
400 /* FIXME: this may be moved to the wtmain.c file, because it may be needed by
401 * others... (windows uses stricmp while Un*x uses strcasecmp...)
403 static int wtstrcasecmp(const char* p1
, const char* p2
)
408 while (c1
== c2
&& c1
)
410 c1
= *p1
++; c2
= *p2
++;
413 c1
= toupper(c1
); c2
= toupper(c2
);
419 static int strCmp(const char* s1
, const char* s2
, BOOL sensitive
)
421 if (!s1
&& !s2
) return 0;
424 return (sensitive
) ? strcmp(s1
, s2
) : wtstrcasecmp(s1
, s2
);
427 static void ok_child_string( int line
, const char *sect
, const char *key
,
428 const char *expect
, int sensitive
)
430 char* result
= getChildString( sect
, key
);
431 ok_(__FILE__
, line
)( strCmp(result
, expect
, sensitive
) == 0, "%s:%s expected '%s', got '%s'\n",
432 sect
, key
, expect
? expect
: "(null)", result
);
435 #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 )
436 #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 )
438 /* using !expect ensures that the test will fail if the sect/key isn't present
441 #define okChildInt(sect, key, expect) \
443 UINT result = GetPrivateProfileIntA((sect), (key), !(expect), resfile); \
444 ok(result == expect, "%s:%s expected %d, but got %d\n", (sect), (key), (int)(expect), result); \
447 static void test_Startup(void)
449 char buffer
[MAX_PATH
];
450 PROCESS_INFORMATION info
;
451 STARTUPINFOA startup
,si
;
452 static CHAR title
[] = "I'm the title string",
453 desktop
[] = "I'm the desktop string",
456 /* let's start simplistic */
457 memset(&startup
, 0, sizeof(startup
));
458 startup
.cb
= sizeof(startup
);
459 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
460 startup
.wShowWindow
= SW_SHOWNORMAL
;
462 get_file_name(resfile
);
463 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
464 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
465 /* wait for child to terminate */
466 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
467 /* child process has changed result file, so let profile functions know about it */
468 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
470 GetStartupInfoA(&si
);
471 okChildInt("StartupInfoA", "cb", startup
.cb
);
472 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
473 okChildString("StartupInfoA", "lpTitle", si
.lpTitle
);
474 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
475 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
476 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
477 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
478 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
479 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
480 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
481 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
482 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
484 assert(DeleteFileA(resfile
) != 0);
486 /* not so simplistic now */
487 memset(&startup
, 0, sizeof(startup
));
488 startup
.cb
= sizeof(startup
);
489 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
490 startup
.wShowWindow
= SW_SHOWNORMAL
;
491 startup
.lpTitle
= title
;
492 startup
.lpDesktop
= desktop
;
493 startup
.dwXCountChars
= 0x12121212;
494 startup
.dwYCountChars
= 0x23232323;
495 startup
.dwX
= 0x34343434;
496 startup
.dwY
= 0x45454545;
497 startup
.dwXSize
= 0x56565656;
498 startup
.dwYSize
= 0x67676767;
499 startup
.dwFillAttribute
= 0xA55A;
501 get_file_name(resfile
);
502 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
503 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
504 /* wait for child to terminate */
505 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
506 /* child process has changed result file, so let profile functions know about it */
507 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
509 okChildInt("StartupInfoA", "cb", startup
.cb
);
510 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
511 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
512 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
513 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
514 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
515 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
516 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
517 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
518 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
519 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
520 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
522 assert(DeleteFileA(resfile
) != 0);
524 /* not so simplistic now */
525 memset(&startup
, 0, sizeof(startup
));
526 startup
.cb
= sizeof(startup
);
527 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
528 startup
.wShowWindow
= SW_SHOWNORMAL
;
529 startup
.lpTitle
= title
;
530 startup
.lpDesktop
= NULL
;
531 startup
.dwXCountChars
= 0x12121212;
532 startup
.dwYCountChars
= 0x23232323;
533 startup
.dwX
= 0x34343434;
534 startup
.dwY
= 0x45454545;
535 startup
.dwXSize
= 0x56565656;
536 startup
.dwYSize
= 0x67676767;
537 startup
.dwFillAttribute
= 0xA55A;
539 get_file_name(resfile
);
540 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
541 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
542 /* wait for child to terminate */
543 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
544 /* child process has changed result file, so let profile functions know about it */
545 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
547 okChildInt("StartupInfoA", "cb", startup
.cb
);
548 okChildString("StartupInfoA", "lpDesktop", si
.lpDesktop
);
549 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
550 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
551 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
552 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
553 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
554 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
555 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
556 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
557 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
558 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
560 assert(DeleteFileA(resfile
) != 0);
562 /* not so simplistic now */
563 memset(&startup
, 0, sizeof(startup
));
564 startup
.cb
= sizeof(startup
);
565 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
566 startup
.wShowWindow
= SW_SHOWNORMAL
;
567 startup
.lpTitle
= title
;
568 startup
.lpDesktop
= empty
;
569 startup
.dwXCountChars
= 0x12121212;
570 startup
.dwYCountChars
= 0x23232323;
571 startup
.dwX
= 0x34343434;
572 startup
.dwY
= 0x45454545;
573 startup
.dwXSize
= 0x56565656;
574 startup
.dwYSize
= 0x67676767;
575 startup
.dwFillAttribute
= 0xA55A;
577 get_file_name(resfile
);
578 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
579 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
580 /* wait for child to terminate */
581 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
582 /* child process has changed result file, so let profile functions know about it */
583 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
585 okChildInt("StartupInfoA", "cb", startup
.cb
);
586 todo_wine
okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
587 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
588 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
589 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
590 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
591 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
592 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
593 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
594 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
595 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
596 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
598 assert(DeleteFileA(resfile
) != 0);
600 /* not so simplistic now */
601 memset(&startup
, 0, sizeof(startup
));
602 startup
.cb
= sizeof(startup
);
603 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
604 startup
.wShowWindow
= SW_SHOWNORMAL
;
605 startup
.lpTitle
= NULL
;
606 startup
.lpDesktop
= desktop
;
607 startup
.dwXCountChars
= 0x12121212;
608 startup
.dwYCountChars
= 0x23232323;
609 startup
.dwX
= 0x34343434;
610 startup
.dwY
= 0x45454545;
611 startup
.dwXSize
= 0x56565656;
612 startup
.dwYSize
= 0x67676767;
613 startup
.dwFillAttribute
= 0xA55A;
615 get_file_name(resfile
);
616 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
617 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
618 /* wait for child to terminate */
619 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
620 /* child process has changed result file, so let profile functions know about it */
621 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
623 okChildInt("StartupInfoA", "cb", startup
.cb
);
624 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
625 okChildString("StartupInfoA", "lpTitle", si
.lpTitle
);
626 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
627 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
628 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
629 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
630 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
631 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
632 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
633 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
634 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
636 assert(DeleteFileA(resfile
) != 0);
638 /* not so simplistic now */
639 memset(&startup
, 0, sizeof(startup
));
640 startup
.cb
= sizeof(startup
);
641 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
642 startup
.wShowWindow
= SW_SHOWNORMAL
;
643 startup
.lpTitle
= empty
;
644 startup
.lpDesktop
= desktop
;
645 startup
.dwXCountChars
= 0x12121212;
646 startup
.dwYCountChars
= 0x23232323;
647 startup
.dwX
= 0x34343434;
648 startup
.dwY
= 0x45454545;
649 startup
.dwXSize
= 0x56565656;
650 startup
.dwYSize
= 0x67676767;
651 startup
.dwFillAttribute
= 0xA55A;
653 get_file_name(resfile
);
654 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
655 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
656 /* wait for child to terminate */
657 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
658 /* child process has changed result file, so let profile functions know about it */
659 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
661 okChildInt("StartupInfoA", "cb", startup
.cb
);
662 okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
663 todo_wine
okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
664 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
665 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
666 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
667 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
668 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
669 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
670 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
671 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
672 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
674 assert(DeleteFileA(resfile
) != 0);
676 /* not so simplistic now */
677 memset(&startup
, 0, sizeof(startup
));
678 startup
.cb
= sizeof(startup
);
679 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
680 startup
.wShowWindow
= SW_SHOWNORMAL
;
681 startup
.lpTitle
= empty
;
682 startup
.lpDesktop
= empty
;
683 startup
.dwXCountChars
= 0x12121212;
684 startup
.dwYCountChars
= 0x23232323;
685 startup
.dwX
= 0x34343434;
686 startup
.dwY
= 0x45454545;
687 startup
.dwXSize
= 0x56565656;
688 startup
.dwYSize
= 0x67676767;
689 startup
.dwFillAttribute
= 0xA55A;
691 get_file_name(resfile
);
692 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
693 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
694 /* wait for child to terminate */
695 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
696 /* child process has changed result file, so let profile functions know about it */
697 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
699 okChildInt("StartupInfoA", "cb", startup
.cb
);
700 todo_wine
okChildString("StartupInfoA", "lpDesktop", startup
.lpDesktop
);
701 todo_wine
okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
702 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
703 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
704 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
705 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
706 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
707 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
708 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
709 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
710 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
712 assert(DeleteFileA(resfile
) != 0);
714 /* TODO: test for A/W and W/A and W/W */
717 static void test_CommandLine(void)
719 char buffer
[MAX_PATH
], fullpath
[MAX_PATH
], *lpFilePart
, *p
;
720 PROCESS_INFORMATION info
;
721 STARTUPINFOA startup
;
725 memset(&startup
, 0, sizeof(startup
));
726 startup
.cb
= sizeof(startup
);
727 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
728 startup
.wShowWindow
= SW_SHOWNORMAL
;
731 get_file_name(resfile
);
732 sprintf(buffer
, "%s tests/process.c %s \"C:\\Program Files\\my nice app.exe\"", selfname
, resfile
);
733 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
734 /* wait for child to terminate */
735 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
736 /* child process has changed result file, so let profile functions know about it */
737 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
739 okChildInt("Arguments", "argcA", 4);
740 okChildString("Arguments", "argvA3", "C:\\Program Files\\my nice app.exe");
741 okChildString("Arguments", "argvA4", NULL
);
742 okChildString("Arguments", "CommandLineA", buffer
);
744 assert(DeleteFileA(resfile
) != 0);
746 memset(&startup
, 0, sizeof(startup
));
747 startup
.cb
= sizeof(startup
);
748 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
749 startup
.wShowWindow
= SW_SHOWNORMAL
;
752 get_file_name(resfile
);
753 sprintf(buffer
, "%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", selfname
, resfile
);
754 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
755 /* wait for child to terminate */
756 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
757 /* child process has changed result file, so let profile functions know about it */
758 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
760 okChildInt("Arguments", "argcA", 6);
761 okChildString("Arguments", "argvA3", "a\"b\\");
762 okChildString("Arguments", "argvA4", "c\"");
763 okChildString("Arguments", "argvA5", "d");
764 okChildString("Arguments", "argvA6", NULL
);
765 okChildString("Arguments", "CommandLineA", buffer
);
767 assert(DeleteFileA(resfile
) != 0);
769 /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
770 get_file_name(resfile
);
771 /* Use exename to avoid buffer containing things like 'C:' */
772 sprintf(buffer
, "./%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
773 SetLastError(0xdeadbeef);
774 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
775 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
776 /* wait for child to terminate */
777 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
778 /* child process has changed result file, so let profile functions know about it */
779 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
780 sprintf(buffer
, "./%s", exename
);
781 okChildString("Arguments", "argvA0", buffer
);
783 assert(DeleteFileA(resfile
) != 0);
785 get_file_name(resfile
);
786 /* Use exename to avoid buffer containing things like 'C:' */
787 sprintf(buffer
, ".\\%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", exename
, resfile
);
788 SetLastError(0xdeadbeef);
789 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
790 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
791 /* wait for child to terminate */
792 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
793 /* child process has changed result file, so let profile functions know about it */
794 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
795 sprintf(buffer
, ".\\%s", exename
);
796 okChildString("Arguments", "argvA0", buffer
);
798 assert(DeleteFileA(resfile
) != 0);
800 get_file_name(resfile
);
801 len
= GetFullPathNameA(selfname
, MAX_PATH
, fullpath
, &lpFilePart
);
802 assert ( lpFilePart
!= 0);
803 *(lpFilePart
-1 ) = 0;
804 p
= strrchr(fullpath
, '\\');
806 /* Use exename to avoid buffer containing things like 'C:' */
807 sprintf(buffer
, "..%s/%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", p
, exename
, resfile
);
808 SetLastError(0xdeadbeef);
809 ret
= CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
);
810 ok(ret
, "CreateProcess (%s) failed : %d\n", buffer
, GetLastError());
811 /* wait for child to terminate */
812 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
813 /* child process has changed result file, so let profile functions know about it */
814 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
815 sprintf(buffer
, "..%s/%s", p
, exename
);
816 okChildString("Arguments", "argvA0", buffer
);
818 assert(DeleteFileA(resfile
) != 0);
822 static void test_Directory(void)
824 char buffer
[MAX_PATH
];
825 PROCESS_INFORMATION info
;
826 STARTUPINFOA startup
;
827 char windir
[MAX_PATH
];
828 static CHAR cmdline
[] = "winver.exe";
830 memset(&startup
, 0, sizeof(startup
));
831 startup
.cb
= sizeof(startup
);
832 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
833 startup
.wShowWindow
= SW_SHOWNORMAL
;
836 get_file_name(resfile
);
837 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
838 GetWindowsDirectoryA( windir
, sizeof(windir
) );
839 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, windir
, &startup
, &info
), "CreateProcess\n");
840 /* wait for child to terminate */
841 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
842 /* child process has changed result file, so let profile functions know about it */
843 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
845 okChildIString("Misc", "CurrDirA", windir
);
847 assert(DeleteFileA(resfile
) != 0);
849 /* search PATH for the exe if directory is NULL */
850 ok(CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
851 ok(TerminateProcess(info
.hProcess
, 0), "Child process termination\n");
853 /* if any directory is provided, don't search PATH, error on bad directory */
854 SetLastError(0xdeadbeef);
855 memset(&info
, 0, sizeof(info
));
856 ok(!CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0L,
857 NULL
, "non\\existent\\directory", &startup
, &info
), "CreateProcess\n");
858 ok(GetLastError() == ERROR_DIRECTORY
, "Expected ERROR_DIRECTORY, got %d\n", GetLastError());
859 ok(!TerminateProcess(info
.hProcess
, 0), "Child process should not exist\n");
862 static BOOL
is_str_env_drive_dir(const char* str
)
864 return str
[0] == '=' && str
[1] >= 'A' && str
[1] <= 'Z' && str
[2] == ':' &&
865 str
[3] == '=' && str
[4] == str
[1];
868 /* compared expected child's environment (in gesA) from actual
869 * environment our child got
871 static void cmpEnvironment(const char* gesA
)
879 clen
= GetPrivateProfileIntA("EnvironmentA", "len", 0, resfile
);
881 /* now look each parent env in child */
882 if ((ptrA
= gesA
) != NULL
)
886 for (i
= 0; i
< clen
; i
++)
888 sprintf(key
, "env%d", i
);
889 res
= getChildString("EnvironmentA", key
);
890 if (strncmp(ptrA
, res
, MAX_LISTED_ENV_VAR
- 1) == 0)
894 ok(found
, "Parent-env string %s isn't in child process\n", ptrA
);
896 ptrA
+= strlen(ptrA
) + 1;
900 /* and each child env in parent */
901 for (i
= 0; i
< clen
; i
++)
903 sprintf(key
, "env%d", i
);
904 res
= getChildString("EnvironmentA", key
);
905 if ((ptrA
= gesA
) != NULL
)
909 if (strncmp(res
, ptrA
, MAX_LISTED_ENV_VAR
- 1) == 0)
911 ptrA
+= strlen(ptrA
) + 1;
913 if (!*ptrA
) ptrA
= NULL
;
916 if (!is_str_env_drive_dir(res
))
918 found
= ptrA
!= NULL
;
919 ok(found
, "Child-env string %s isn't in parent process\n", res
);
921 /* else => should also test we get the right per drive default directory here... */
925 static void test_Environment(void)
927 char buffer
[MAX_PATH
];
928 PROCESS_INFORMATION info
;
929 STARTUPINFOA startup
;
936 memset(&startup
, 0, sizeof(startup
));
937 startup
.cb
= sizeof(startup
);
938 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
939 startup
.wShowWindow
= SW_SHOWNORMAL
;
942 get_file_name(resfile
);
943 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
944 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
945 /* wait for child to terminate */
946 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
947 /* child process has changed result file, so let profile functions know about it */
948 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
950 cmpEnvironment(GetEnvironmentStringsA());
952 assert(DeleteFileA(resfile
) != 0);
954 memset(&startup
, 0, sizeof(startup
));
955 startup
.cb
= sizeof(startup
);
956 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
957 startup
.wShowWindow
= SW_SHOWNORMAL
;
960 get_file_name(resfile
);
961 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
964 ptr
= GetEnvironmentStringsA();
967 slen
= strlen(ptr
)+1;
968 child_env_len
+= slen
;
971 /* Add space for additional environment variables */
972 child_env_len
+= 256;
973 child_env
= HeapAlloc(GetProcessHeap(), 0, child_env_len
);
976 sprintf(ptr
, "=%c:=%s", 'C', "C:\\FOO\\BAR");
977 ptr
+= strlen(ptr
) + 1;
978 strcpy(ptr
, "PATH=C:\\WINDOWS;C:\\WINDOWS\\SYSTEM;C:\\MY\\OWN\\DIR");
979 ptr
+= strlen(ptr
) + 1;
980 strcpy(ptr
, "FOO=BAR");
981 ptr
+= strlen(ptr
) + 1;
982 strcpy(ptr
, "BAR=FOOBAR");
983 ptr
+= strlen(ptr
) + 1;
984 /* copy all existing variables except:
986 * - PATH (already set above)
987 * - the directory definitions (=[A-Z]:=)
989 for (env
= GetEnvironmentStringsA(); *env
; env
+= strlen(env
) + 1)
991 if (strncmp(env
, "PATH=", 5) != 0 &&
992 strncmp(env
, "WINELOADER=", 11) != 0 &&
993 !is_str_env_drive_dir(env
))
996 ptr
+= strlen(ptr
) + 1;
1000 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0L, child_env
, NULL
, &startup
, &info
), "CreateProcess\n");
1001 /* wait for child to terminate */
1002 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1003 /* child process has changed result file, so let profile functions know about it */
1004 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1006 cmpEnvironment(child_env
);
1008 HeapFree(GetProcessHeap(), 0, child_env
);
1010 assert(DeleteFileA(resfile
) != 0);
1013 static void test_SuspendFlag(void)
1015 char buffer
[MAX_PATH
];
1016 PROCESS_INFORMATION info
;
1017 STARTUPINFOA startup
, us
;
1020 /* let's start simplistic */
1021 memset(&startup
, 0, sizeof(startup
));
1022 startup
.cb
= sizeof(startup
);
1023 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1024 startup
.wShowWindow
= SW_SHOWNORMAL
;
1026 get_file_name(resfile
);
1027 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
1028 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, CREATE_SUSPENDED
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1030 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1032 ok(GetExitCodeThread(info
.hThread
, &exit_status
) && exit_status
== STILL_ACTIVE
, "thread still running\n");
1033 ok(ResumeThread(info
.hThread
) == 1, "Resuming thread\n");
1035 /* wait for child to terminate */
1036 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1037 /* child process has changed result file, so let profile functions know about it */
1038 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1040 GetStartupInfoA(&us
);
1042 okChildInt("StartupInfoA", "cb", startup
.cb
);
1043 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1044 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
1045 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1046 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1047 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1048 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1049 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1050 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1051 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1052 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1053 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1055 assert(DeleteFileA(resfile
) != 0);
1058 static void test_DebuggingFlag(void)
1060 char buffer
[MAX_PATH
];
1061 PROCESS_INFORMATION info
;
1062 STARTUPINFOA startup
, us
;
1066 /* let's start simplistic */
1067 memset(&startup
, 0, sizeof(startup
));
1068 startup
.cb
= sizeof(startup
);
1069 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1070 startup
.wShowWindow
= SW_SHOWNORMAL
;
1072 get_file_name(resfile
);
1073 sprintf(buffer
, "%s tests/process.c %s", selfname
, resfile
);
1074 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, DEBUG_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1076 /* get all startup events up to the entry point break exception */
1079 ok(WaitForDebugEvent(&de
, INFINITE
), "reading debug event\n");
1080 ContinueDebugEvent(de
.dwProcessId
, de
.dwThreadId
, DBG_CONTINUE
);
1081 if (de
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
) dbg
++;
1082 } while (de
.dwDebugEventCode
!= EXIT_PROCESS_DEBUG_EVENT
);
1084 ok(dbg
, "I have seen a debug event\n");
1085 /* wait for child to terminate */
1086 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1087 /* child process has changed result file, so let profile functions know about it */
1088 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1090 GetStartupInfoA(&us
);
1092 okChildInt("StartupInfoA", "cb", startup
.cb
);
1093 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1094 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
1095 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1096 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1097 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1098 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1099 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1100 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1101 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1102 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1103 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1105 assert(DeleteFileA(resfile
) != 0);
1108 static BOOL
is_console(HANDLE h
)
1110 return h
!= INVALID_HANDLE_VALUE
&& ((ULONG_PTR
)h
& 3) == 3;
1113 static void test_Console(void)
1115 char buffer
[MAX_PATH
];
1116 PROCESS_INFORMATION info
;
1117 STARTUPINFOA startup
, us
;
1118 SECURITY_ATTRIBUTES sa
;
1119 CONSOLE_SCREEN_BUFFER_INFO sbi
, sbiC
;
1120 DWORD modeIn
, modeOut
, modeInC
, modeOutC
;
1121 DWORD cpIn
, cpOut
, cpInC
, cpOutC
;
1123 HANDLE hChildIn
, hChildInInh
, hChildOut
, hChildOutInh
, hParentIn
, hParentOut
;
1124 const char* msg
= "This is a std-handle inheritance test.";
1127 memset(&startup
, 0, sizeof(startup
));
1128 startup
.cb
= sizeof(startup
);
1129 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1130 startup
.wShowWindow
= SW_SHOWNORMAL
;
1132 sa
.nLength
= sizeof(sa
);
1133 sa
.lpSecurityDescriptor
= NULL
;
1134 sa
.bInheritHandle
= TRUE
;
1136 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1137 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1139 /* first, we need to be sure we're attached to a console */
1140 if (!is_console(startup
.hStdInput
) || !is_console(startup
.hStdOutput
))
1142 /* we're not attached to a console, let's do it */
1144 startup
.hStdInput
= CreateFileA("CONIN$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1145 startup
.hStdOutput
= CreateFileA("CONOUT$", GENERIC_READ
|GENERIC_WRITE
, 0, &sa
, OPEN_EXISTING
, 0, 0);
1147 /* now verify everything's ok */
1148 ok(startup
.hStdInput
!= INVALID_HANDLE_VALUE
, "Opening ConIn\n");
1149 ok(startup
.hStdOutput
!= INVALID_HANDLE_VALUE
, "Opening ConOut\n");
1150 startup
.hStdError
= startup
.hStdOutput
;
1152 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbi
), "Getting sb info\n");
1153 ok(GetConsoleMode(startup
.hStdInput
, &modeIn
) &&
1154 GetConsoleMode(startup
.hStdOutput
, &modeOut
), "Getting console modes\n");
1155 cpIn
= GetConsoleCP();
1156 cpOut
= GetConsoleOutputCP();
1158 get_file_name(resfile
);
1159 sprintf(buffer
, "%s tests/process.c %s console", selfname
, resfile
);
1160 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1162 /* wait for child to terminate */
1163 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1164 /* child process has changed result file, so let profile functions know about it */
1165 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1167 /* now get the modification the child has made, and resets parents expected values */
1168 ok(GetConsoleScreenBufferInfo(startup
.hStdOutput
, &sbiC
), "Getting sb info\n");
1169 ok(GetConsoleMode(startup
.hStdInput
, &modeInC
) &&
1170 GetConsoleMode(startup
.hStdOutput
, &modeOutC
), "Getting console modes\n");
1172 SetConsoleMode(startup
.hStdInput
, modeIn
);
1173 SetConsoleMode(startup
.hStdOutput
, modeOut
);
1175 cpInC
= GetConsoleCP();
1176 cpOutC
= GetConsoleOutputCP();
1178 /* Try to set invalid CP */
1179 SetLastError(0xdeadbeef);
1180 ok(!SetConsoleCP(0), "Shouldn't succeed\n");
1181 ok(GetLastError()==ERROR_INVALID_PARAMETER
,
1182 "GetLastError: expecting %u got %u\n",
1183 ERROR_INVALID_PARAMETER
, GetLastError());
1185 SetLastError(0xdeadbeef);
1186 ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n");
1187 ok(GetLastError()==ERROR_INVALID_PARAMETER
,
1188 "GetLastError: expecting %u got %u\n",
1189 ERROR_INVALID_PARAMETER
, GetLastError());
1192 SetConsoleOutputCP(cpOut
);
1194 GetStartupInfoA(&us
);
1196 okChildInt("StartupInfoA", "cb", startup
.cb
);
1197 okChildString("StartupInfoA", "lpDesktop", us
.lpDesktop
);
1198 okChildString("StartupInfoA", "lpTitle", startup
.lpTitle
);
1199 okChildInt("StartupInfoA", "dwX", startup
.dwX
);
1200 okChildInt("StartupInfoA", "dwY", startup
.dwY
);
1201 okChildInt("StartupInfoA", "dwXSize", startup
.dwXSize
);
1202 okChildInt("StartupInfoA", "dwYSize", startup
.dwYSize
);
1203 okChildInt("StartupInfoA", "dwXCountChars", startup
.dwXCountChars
);
1204 okChildInt("StartupInfoA", "dwYCountChars", startup
.dwYCountChars
);
1205 okChildInt("StartupInfoA", "dwFillAttribute", startup
.dwFillAttribute
);
1206 okChildInt("StartupInfoA", "dwFlags", startup
.dwFlags
);
1207 okChildInt("StartupInfoA", "wShowWindow", startup
.wShowWindow
);
1209 /* check child correctly inherited the console */
1210 okChildInt("StartupInfoA", "hStdInput", (DWORD
)startup
.hStdInput
);
1211 okChildInt("StartupInfoA", "hStdOutput", (DWORD
)startup
.hStdOutput
);
1212 okChildInt("StartupInfoA", "hStdError", (DWORD
)startup
.hStdError
);
1213 okChildInt("Console", "SizeX", (DWORD
)sbi
.dwSize
.X
);
1214 okChildInt("Console", "SizeY", (DWORD
)sbi
.dwSize
.Y
);
1215 okChildInt("Console", "CursorX", (DWORD
)sbi
.dwCursorPosition
.X
);
1216 okChildInt("Console", "CursorY", (DWORD
)sbi
.dwCursorPosition
.Y
);
1217 okChildInt("Console", "Attributes", sbi
.wAttributes
);
1218 okChildInt("Console", "winLeft", (DWORD
)sbi
.srWindow
.Left
);
1219 okChildInt("Console", "winTop", (DWORD
)sbi
.srWindow
.Top
);
1220 okChildInt("Console", "winRight", (DWORD
)sbi
.srWindow
.Right
);
1221 okChildInt("Console", "winBottom", (DWORD
)sbi
.srWindow
.Bottom
);
1222 okChildInt("Console", "maxWinWidth", (DWORD
)sbi
.dwMaximumWindowSize
.X
);
1223 okChildInt("Console", "maxWinHeight", (DWORD
)sbi
.dwMaximumWindowSize
.Y
);
1224 okChildInt("Console", "InputCP", cpIn
);
1225 okChildInt("Console", "OutputCP", cpOut
);
1226 okChildInt("Console", "InputMode", modeIn
);
1227 okChildInt("Console", "OutputMode", modeOut
);
1229 ok(cpInC
== 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC
, cpIn
);
1230 ok(cpOutC
== 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC
, cpOut
);
1231 ok(modeInC
== (modeIn
^ 1), "Wrong console mode\n");
1232 ok(modeOutC
== (modeOut
^ 1), "Wrong console-SB mode\n");
1233 ok(sbiC
.dwCursorPosition
.X
== (sbi
.dwCursorPosition
.X
^ 1), "Wrong cursor position\n");
1234 ok(sbiC
.dwCursorPosition
.Y
== (sbi
.dwCursorPosition
.Y
^ 1), "Wrong cursor position\n");
1237 assert(DeleteFileA(resfile
) != 0);
1239 ok(CreatePipe(&hParentIn
, &hChildOut
, NULL
, 0), "Creating parent-input pipe\n");
1240 ok(DuplicateHandle(GetCurrentProcess(), hChildOut
, GetCurrentProcess(),
1241 &hChildOutInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1242 "Duplicating as inheritable child-output pipe\n");
1243 CloseHandle(hChildOut
);
1245 ok(CreatePipe(&hChildIn
, &hParentOut
, NULL
, 0), "Creating parent-output pipe\n");
1246 ok(DuplicateHandle(GetCurrentProcess(), hChildIn
, GetCurrentProcess(),
1247 &hChildInInh
, 0, TRUE
, DUPLICATE_SAME_ACCESS
),
1248 "Duplicating as inheritable child-input pipe\n");
1249 CloseHandle(hChildIn
);
1251 memset(&startup
, 0, sizeof(startup
));
1252 startup
.cb
= sizeof(startup
);
1253 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
1254 startup
.wShowWindow
= SW_SHOWNORMAL
;
1255 startup
.hStdInput
= hChildInInh
;
1256 startup
.hStdOutput
= hChildOutInh
;
1257 startup
.hStdError
= hChildOutInh
;
1259 get_file_name(resfile
);
1260 sprintf(buffer
, "%s tests/process.c %s stdhandle", selfname
, resfile
);
1261 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1262 ok(CloseHandle(hChildInInh
), "Closing handle\n");
1263 ok(CloseHandle(hChildOutInh
), "Closing handle\n");
1265 msg_len
= strlen(msg
) + 1;
1266 ok(WriteFile(hParentOut
, msg
, msg_len
, &w
, NULL
), "Writing to child\n");
1267 ok(w
== msg_len
, "Should have written %u bytes, actually wrote %u\n", msg_len
, w
);
1268 memset(buffer
, 0, sizeof(buffer
));
1269 ok(ReadFile(hParentIn
, buffer
, sizeof(buffer
), &w
, NULL
), "Reading from child\n");
1270 ok(strcmp(buffer
, msg
) == 0, "Should have received '%s'\n", msg
);
1272 /* wait for child to terminate */
1273 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1274 /* child process has changed result file, so let profile functions know about it */
1275 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1277 okChildString("StdHandle", "msg", msg
);
1280 assert(DeleteFileA(resfile
) != 0);
1283 static void test_ExitCode(void)
1285 char buffer
[MAX_PATH
];
1286 PROCESS_INFORMATION info
;
1287 STARTUPINFOA startup
;
1290 /* let's start simplistic */
1291 memset(&startup
, 0, sizeof(startup
));
1292 startup
.cb
= sizeof(startup
);
1293 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
1294 startup
.wShowWindow
= SW_SHOWNORMAL
;
1296 get_file_name(resfile
);
1297 sprintf(buffer
, "%s tests/process.c %s exit_code", selfname
, resfile
);
1298 ok(CreateProcessA(NULL
, buffer
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
), "CreateProcess\n");
1300 /* wait for child to terminate */
1301 ok(WaitForSingleObject(info
.hProcess
, 30000) == WAIT_OBJECT_0
, "Child process termination\n");
1302 /* child process has changed result file, so let profile functions know about it */
1303 WritePrivateProfileStringA(NULL
, NULL
, NULL
, resfile
);
1305 ok(GetExitCodeProcess(info
.hProcess
, &code
), "Getting exit code\n");
1306 okChildInt("ExitCode", "value", code
);
1309 assert(DeleteFileA(resfile
) != 0);
1312 static void test_OpenProcess(void)
1316 MEMORY_BASIC_INFORMATION info
;
1317 SIZE_T dummy
, read_bytes
;
1319 /* not exported in all windows versions */
1320 if ((!pVirtualAllocEx
) || (!pVirtualFreeEx
)) {
1321 skip("VirtualAllocEx not found\n");
1325 /* without PROCESS_VM_OPERATION */
1326 hproc
= OpenProcess(PROCESS_ALL_ACCESS
& ~PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1327 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1329 SetLastError(0xdeadbeef);
1330 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1331 ok(!addr1
, "VirtualAllocEx should fail\n");
1332 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1335 skip("VirtualAllocEx not implemented\n");
1338 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1340 read_bytes
= 0xdeadbeef;
1341 SetLastError(0xdeadbeef);
1342 ok(ReadProcessMemory(hproc
, test_OpenProcess
, &dummy
, sizeof(dummy
), &read_bytes
),
1343 "ReadProcessMemory error %d\n", GetLastError());
1344 ok(read_bytes
== sizeof(dummy
), "wrong read bytes %ld\n", read_bytes
);
1348 hproc
= OpenProcess(PROCESS_VM_OPERATION
, FALSE
, GetCurrentProcessId());
1349 ok(hproc
!= NULL
, "OpenProcess error %d\n", GetLastError());
1351 addr1
= pVirtualAllocEx(hproc
, 0, 0xFFFC, MEM_RESERVE
, PAGE_NOACCESS
);
1352 ok(addr1
!= NULL
, "VirtualAllocEx error %d\n", GetLastError());
1354 /* without PROCESS_QUERY_INFORMATION */
1355 SetLastError(0xdeadbeef);
1356 ok(!VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)),
1357 "VirtualQueryEx without PROCESS_QUERY_INFORMATION rights should fail\n");
1358 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1360 /* without PROCESS_VM_READ */
1361 read_bytes
= 0xdeadbeef;
1362 SetLastError(0xdeadbeef);
1363 ok(!ReadProcessMemory(hproc
, addr1
, &dummy
, sizeof(dummy
), &read_bytes
),
1364 "ReadProcessMemory without PROCESS_VM_READ rights should fail\n");
1365 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1366 ok(read_bytes
== 0, "wrong read bytes %ld\n", read_bytes
);
1370 hproc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, GetCurrentProcessId());
1372 memset(&info
, 0xcc, sizeof(info
));
1373 ok(VirtualQueryEx(hproc
, addr1
, &info
, sizeof(info
)) == sizeof(info
),
1374 "VirtualQueryEx error %d\n", GetLastError());
1376 ok(info
.BaseAddress
== addr1
, "%p != %p\n", info
.BaseAddress
, addr1
);
1377 ok(info
.AllocationBase
== addr1
, "%p != %p\n", info
.AllocationBase
, addr1
);
1378 ok(info
.AllocationProtect
== PAGE_NOACCESS
, "%x != PAGE_NOACCESS\n", info
.AllocationProtect
);
1379 ok(info
.RegionSize
== 0x10000, "%lx != 0x10000\n", info
.RegionSize
);
1380 ok(info
.State
== MEM_RESERVE
, "%x != MEM_RESERVE\n", info
.State
);
1381 /* NT reports Protect == 0 for a not committed memory block */
1382 ok(info
.Protect
== 0 /* NT */ ||
1383 info
.Protect
== PAGE_NOACCESS
, /* Win9x */
1384 "%x != PAGE_NOACCESS\n", info
.Protect
);
1385 ok(info
.Type
== MEM_PRIVATE
, "%x != MEM_PRIVATE\n", info
.Type
);
1387 SetLastError(0xdeadbeef);
1388 ok(!pVirtualFreeEx(hproc
, addr1
, 0, MEM_RELEASE
),
1389 "VirtualFreeEx without PROCESS_VM_OPERATION rights should fail\n");
1390 ok(GetLastError() == ERROR_ACCESS_DENIED
, "wrong error %d\n", GetLastError());
1394 ok(VirtualFree(addr1
, 0, MEM_RELEASE
), "VirtualFree failed\n");
1400 ok(b
, "Basic init of CreateProcess test\n");
1405 doChild(myARGV
[2], (myARGC
== 3) ? NULL
: myARGV
[3]);
1413 test_DebuggingFlag();
1417 /* things that can be tested:
1418 * lookup: check the way program to be executed is searched
1419 * handles: check the handle inheritance stuff (+sec options)
1420 * console: check if console creation parameters work