Various new tests for CreateProcess showing a couple of issues in current implementation.
-- v2: ntdll,server: Revisit std handles inheritance. kernelbase: Reset std handles in startup_info when not requested. kernel32/tests: Add more tests about CreateProcess. kernel32/tests: Introduce a new infrastructure for testing CreateProcess().
From: Eric Pouech epouech@codeweavers.com
Move a couple of existing tests to this infrastructure.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/process.c | 398 ++++++++++++++++++++++++---------- 1 file changed, 282 insertions(+), 116 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 8bb2748f8e1..4d99b43d9b0 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -317,6 +317,37 @@ static void WINAPIV __WINE_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fm WriteFile(h, buffer, strlen(buffer), &w, NULL); }
+/* bits 0..1 contains FILE_TYPE_{UNKNOWN, CHAR, PIPE, DISK} */ +#define HATTR_NULL 0x08 /* NULL handle value */ +#define HATTR_INVALID 0x04 /* INVALID_HANDLE_VALUE */ +#define HATTR_TYPE 0x0c /* valid handle, with type set */ +#define HATTR_INHERIT 0x10 /* inheritance flag set */ + +static unsigned encode_handle_attributes(HANDLE h) +{ + DWORD dw; + unsigned result; + + if (h == NULL) + result = HATTR_NULL; + else if (h == INVALID_HANDLE_VALUE) + result = HATTR_INVALID; + else + { + result = HATTR_TYPE; + dw = GetFileType(h); + if (dw == FILE_TYPE_CHAR || dw == FILE_TYPE_DISK || dw == FILE_TYPE_PIPE) + { + DWORD info; + if (GetHandleInformation(h, &info) && (info & HANDLE_FLAG_INHERIT)) + result |= HATTR_INHERIT; + } + else + dw = FILE_TYPE_UNKNOWN; + result |= dw; + } + return result; +}
/****************************************************************** * doChild @@ -347,17 +378,24 @@ static void doChild(const char* file, const char* option) "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n" "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n" "dwFlags=%lu\nwShowWindow=%u\n" - "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n", + "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n" + "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n", siA.cb, encodeA(siA.lpDesktop), encodeA(siA.lpTitle), siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize, siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute, siA.dwFlags, siA.wShowWindow, - (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError); + (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError, + encode_handle_attributes(siA.hStdInput), encode_handle_attributes(siA.hStdOutput), + encode_handle_attributes(siA.hStdError));
/* check the console handles in the TEB */ - childPrintf(hFile, "[TEB]\nhStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n", + childPrintf(hFile, + "[TEB]\nhStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n" + "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n", (DWORD_PTR)params->hStdInput, (DWORD_PTR)params->hStdOutput, - (DWORD_PTR)params->hStdError); + (DWORD_PTR)params->hStdError, + encode_handle_attributes(params->hStdInput), encode_handle_attributes(params->hStdOutput), + encode_handle_attributes(params->hStdError));
/* since GetStartupInfoW is only implemented in win2k, * zero out before calling so we can notice the difference @@ -369,12 +407,15 @@ static void doChild(const char* file, const char* option) "dwX=%lu\ndwY=%lu\ndwXSize=%lu\ndwYSize=%lu\n" "dwXCountChars=%lu\ndwYCountChars=%lu\ndwFillAttribute=%lu\n" "dwFlags=%lu\nwShowWindow=%u\n" - "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n\n", + "hStdInput=%Iu\nhStdOutput=%Iu\nhStdError=%Iu\n" + "hStdInputEncode=%u\nhStdOutputEncode=%u\nhStdErrorEncode=%u\n\n", siW.cb, encodeW(siW.lpDesktop), encodeW(siW.lpTitle), siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize, siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute, siW.dwFlags, siW.wShowWindow, - (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError); + (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError, + encode_handle_attributes(siW.hStdInput), encode_handle_attributes(siW.hStdOutput), + encode_handle_attributes(siW.hStdError));
/* Arguments */ childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC); @@ -595,10 +636,17 @@ static void ok_child_int( int line, const char *sect, const char *key, UINT expe ok_(__FILE__, line)( result == expect, "%s:%s expected %u, but got %u\n", sect, key, expect, result ); }
+static inline void ok_child_hexint( int line, const char *sect, const char *key, UINT expect, UINT is_broken ) +{ + UINT result = GetPrivateProfileIntA( sect, key, !expect, resfile ); + ok_(__FILE__, line)( result == expect || broken( is_broken && result == is_broken ), "%s:%s expected %#x, but got %#x\n", sect, key, expect, result ); +} + #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 ) #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 ) #define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 ) #define okChildInt(sect, key, expect) ok_child_int(__LINE__, (sect), (key), (expect)) +#define okChildHexInt(sect, key, expect, is_broken) ok_child_hexint(__LINE__, (sect), (key), (expect), (is_broken))
static void test_Startup(void) { @@ -3057,72 +3105,245 @@ static void test_BreakawayOk(HANDLE parent_job) ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); }
-static void test_StartupNoConsole(void) +/* copy an executable, but changing its subsystem */ +static inline void copy_change_subsystem(const char* in, const char* out, DWORD subsyst) +{ + BOOL ret; + HANDLE hFile, hMap; + void* mapping; + IMAGE_NT_HEADERS *nthdr; + + ret = CopyFileA(in, out, FALSE); + ok(ret, "Failed to copy executable %s in %s (%lu)\n", in, out, GetLastError()); + + hFile = CreateFileA(out, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "Couldn't open file %s (%lu)\n", out, GetLastError()); + hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); + ok(hMap != NULL, "Couldn't create map (%lu)\n", GetLastError()); + mapping = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); + ok(mapping != NULL, "Couldn't map (%lu)\n", GetLastError()); + nthdr = RtlImageNtHeader(mapping); + ok(nthdr != NULL, "Cannot get NT headers out of %s\n", out); + if (nthdr) nthdr->OptionalHeader.Subsystem = subsyst; + ret = UnmapViewOfFile(mapping); + ok(ret, "Couldn't unmap (%lu)\n", GetLastError()); + CloseHandle(hMap); + CloseHandle(hFile); +} + +#define H_CONSOLE 0 +#define H_DISK 1 + +#define ARG_STD 0x80000000 +#define ARG_STARTUPINFO 0x00000000 +#define ARG_CP_INHERIT 0x40000000 +#define ARG_HANDLE_INHERIT 0x20000000 +#define ARG_HANDLE_MASK (~0xff000000) + +static inline BOOL check_run_child(const char *exec, DWORD flags, BOOL cp_inherit, + STARTUPINFOA *si) { -#ifndef _WIN64 - char buffer[2 * MAX_PATH + 25]; - STARTUPINFOA startup; PROCESS_INFORMATION info; + char buffer[2 * MAX_PATH + 64]; + DWORD exit_code; + BOOL res; + DWORD ret;
- memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW; - startup.wShowWindow = SW_SHOWNORMAL; get_file_name(resfile); - sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); - ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, - &info), "CreateProcess\n"); - wait_and_close_child_process(&info); + sprintf(buffer, ""%s" process dump "%s"", exec, resfile);
- reload_child_info(resfile); - okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE); - okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE); - okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE); - okChildInt("TEB", "hStdInput", 0); - okChildInt("TEB", "hStdOutput", 0); - okChildInt("TEB", "hStdError", 0); - release_memory(); - DeleteFileA(resfile); -#endif + res = CreateProcessA(NULL, buffer, NULL, NULL, cp_inherit, flags, NULL, NULL, si, &info); + ok(res, "CreateProcess failed: %lu %s\n", GetLastError(), buffer); + CloseHandle(info.hThread); + ret = WaitForSingleObject(info.hProcess, 30000); + ok(ret == WAIT_OBJECT_0, "Could not wait for the child process: %ld le=%lu\n", + ret, GetLastError()); + res = GetExitCodeProcess(info.hProcess, &exit_code); + ok(res && exit_code == 0, "Couldn't get exit_code\n"); + CloseHandle(info.hProcess); + return res; }
-static void test_DetachConsoleHandles(void) +static char std_handle_file[MAX_PATH]; + +static inline BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HANDLE hstd[2] ) +{ + BOOL needs_close = FALSE; + BOOL ret; + + memset(startup, 0, sizeof(*startup)); + startup->cb = sizeof(*startup); + + switch (args & ARG_HANDLE_MASK) + { + case H_CONSOLE: + hstd[0] = CreateFileA("CONIN$", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to console\n"); + hstd[1] = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to console\n"); + needs_close = TRUE; + break; + case H_DISK: + hstd[0] = CreateFileA(std_handle_file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file); + hstd[1] = CreateFileA(std_handle_file, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file); + needs_close = TRUE; + break; + default: + ok(0, "Unsupported handle type %x\n", args & ARG_HANDLE_MASK); + return FALSE; + } + if (args & ARG_HANDLE_INHERIT) + { + ret = SetHandleInformation(hstd[0], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + ok(ret, "Couldn't set inherit flag to hstd[0]\n"); + ret = SetHandleInformation(hstd[1], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + ok(ret, "Couldn't set inherit flag to hstd[1]\n"); + } + + if (args & ARG_STD) + { + SetStdHandle(STD_INPUT_HANDLE, hstd[0]); + SetStdHandle(STD_OUTPUT_HANDLE, hstd[1]); + } + else /* through startup info */ + { + startup->dwFlags |= STARTF_USESTDHANDLES; + startup->hStdInput = hstd[0]; + startup->hStdOutput = hstd[1]; + } + return needs_close; +} + +struct std_handle_test +{ + /* input */ + unsigned args; + /* output */ + DWORD expected; + unsigned is_todo; /* bitmask: 1 on TEB values, 2 on StartupInfoA values, 4 on StartupInfoW values */ + DWORD is_broken; /* Win7 broken file types */ +}; + +static void test_StdHandleInheritance(void) { #ifndef _WIN64 - char buffer[2 * MAX_PATH + 25]; - STARTUPINFOA startup; - PROCESS_INFORMATION info; - UINT result; + HANDLE hsavestd[3]; + static char guiexec[MAX_PATH]; + static char cuiexec[MAX_PATH]; + char **argv; + BOOL ret; + int i, j;
- memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; - startup.wShowWindow = SW_SHOWNORMAL; - startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - startup.hStdError = GetStdHandle(STD_ERROR_HANDLE); - get_file_name(resfile); - sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); - ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, - &info), "CreateProcess\n"); - wait_and_close_child_process(&info); + static const struct std_handle_test + detached_cui[] = + { + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + /* all others handles type behave as H_DISK */ + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + }, + detached_gui[] = + { + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + /* all others handles type behave as H_DISK */ + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + }; + static const struct + { + DWORD cp_flags; + BOOL use_cui; + const struct std_handle_test* tests; + size_t count; + const char* descr; + } + tests[] = + { +#define X(d, cg, s) {(d), (cg), s, ARRAY_SIZE(s), #s} + X(DETACHED_PROCESS, TRUE, detached_cui), + X(DETACHED_PROCESS, FALSE, detached_gui), +#undef X + };
- reload_child_info(resfile); - result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); - result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile); - ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result); + hsavestd[0] = GetStdHandle(STD_INPUT_HANDLE); + hsavestd[1] = GetStdHandle(STD_OUTPUT_HANDLE); + hsavestd[2] = GetStdHandle(STD_ERROR_HANDLE);
- release_memory(); - DeleteFileA(resfile); + winetest_get_mainargs(&argv); + + GetTempPathA(ARRAY_SIZE(guiexec), guiexec); + strcat(guiexec, "process_gui.exe"); + copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI); + GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec); + strcat(cuiexec, "process_cui.exe"); + copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI); + get_file_name(std_handle_file); + + for (j = 0; j < ARRAY_SIZE(tests); j++) + { + const struct std_handle_test* std_tests = tests[j].tests; + + for (i = 0; i < tests[j].count; i++) + { + STARTUPINFOA startup; + HANDLE hstd[2] = {}; + BOOL needs_close; + unsigned startup_expected; + + winetest_push_context("%s[%u] ", tests[j].descr, i); + needs_close = build_startupinfo( &startup, std_tests[i].args, hstd ); + + ret = check_run_child(tests[j].use_cui ? cuiexec : guiexec, + tests[j].cp_flags, !!(std_tests[i].args & ARG_CP_INHERIT), + &startup); + ok(ret, "Couldn't run child\n"); + reload_child_info(resfile); + + startup_expected = (std_tests[i].args & ARG_STD) ? HATTR_INVALID : std_tests[i].expected; + + todo_wine_if(std_tests[i].is_todo & 2) + { + okChildHexInt("StartupInfoA", "hStdInputEncode", startup_expected, std_tests[i].is_broken); + okChildHexInt("StartupInfoA", "hStdOutputEncode", startup_expected, std_tests[i].is_broken); + } + + startup_expected = (std_tests[i].args & ARG_STD) ? HATTR_NULL : std_tests[i].expected; + + todo_wine_if(std_tests[i].is_todo & 4) + { + okChildHexInt("StartupInfoW", "hStdInputEncode", startup_expected, std_tests[i].is_broken); + okChildHexInt("StartupInfoW", "hStdOutputEncode", startup_expected, std_tests[i].is_broken); + } + + todo_wine_if(std_tests[i].is_todo & 1) + { + okChildHexInt("TEB", "hStdInputEncode", std_tests[i].expected, std_tests[i].is_broken); + okChildHexInt("TEB", "hStdOutputEncode", std_tests[i].expected, std_tests[i].is_broken); + } + + release_memory(); + DeleteFileA(resfile); + if (needs_close) + { + CloseHandle(hstd[0]); + CloseHandle(hstd[1]); + } + winetest_pop_context(); + } + } + + DeleteFileA(guiexec); + DeleteFileA(cuiexec); + DeleteFileA(std_handle_file); + + SetStdHandle(STD_INPUT_HANDLE, hsavestd[0]); + SetStdHandle(STD_OUTPUT_HANDLE, hsavestd[1]); + SetStdHandle(STD_ERROR_HANDLE, hsavestd[2]); #endif }
@@ -3568,59 +3789,6 @@ static void test_SuspendProcessState(void) } #endif
-static void test_DetachStdHandles(void) -{ -#ifndef _WIN64 - char buffer[2 * MAX_PATH + 25], tempfile[MAX_PATH]; - STARTUPINFOA startup; - PROCESS_INFORMATION info; - HANDLE hstdin, hstdout, hstderr, htemp; - BOOL res; - - hstdin = GetStdHandle(STD_INPUT_HANDLE); - hstdout = GetStdHandle(STD_OUTPUT_HANDLE); - hstderr = GetStdHandle(STD_ERROR_HANDLE); - - get_file_name(tempfile); - htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n"); - - memset(&startup, 0, sizeof(startup)); - startup.cb = sizeof(startup); - startup.dwFlags = STARTF_USESHOWWINDOW; - startup.wShowWindow = SW_SHOWNORMAL; - get_file_name(resfile); - sprintf(buffer, ""%s" process dump "%s"", selfname, resfile); - - SetStdHandle(STD_INPUT_HANDLE, htemp); - SetStdHandle(STD_OUTPUT_HANDLE, htemp); - SetStdHandle(STD_ERROR_HANDLE, htemp); - - res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup, - &info); - - SetStdHandle(STD_INPUT_HANDLE, hstdin); - SetStdHandle(STD_OUTPUT_HANDLE, hstdout); - SetStdHandle(STD_ERROR_HANDLE, hstderr); - - ok(res, "CreateProcess failed\n"); - wait_and_close_child_process(&info); - - reload_child_info(resfile); - okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE); - okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE); - okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE); - okChildInt("TEB", "hStdInput", 0); - okChildInt("TEB", "hStdOutput", 0); - okChildInt("TEB", "hStdError", 0); - release_memory(); - DeleteFileA(resfile); - - CloseHandle(htemp); - DeleteFileA(tempfile); -#endif -} - static void test_GetNumaProcessorNode(void) { SYSTEM_INFO si; @@ -5105,9 +5273,7 @@ START_TEST(process) test_ProcessorCount(); test_RegistryQuota(); test_DuplicateHandle(); - test_StartupNoConsole(); - test_DetachConsoleHandles(); - test_DetachStdHandles(); + test_StdHandleInheritance(); test_GetNumaProcessorNode(); test_session_info(); test_GetLogicalProcessorInformationEx();
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/process.c | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 4d99b43d9b0..252e1829ab9 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -3134,6 +3134,8 @@ static inline void copy_change_subsystem(const char* in, const char* out, DWORD
#define H_CONSOLE 0 #define H_DISK 1 +#define H_CHAR 2 +#define H_PIPE 3
#define ARG_STD 0x80000000 #define ARG_STARTUPINFO 0x00000000 @@ -3191,6 +3193,18 @@ static inline BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HAND ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to file %s\n", std_handle_file); needs_close = TRUE; break; + case H_CHAR: + hstd[0] = CreateFileA("NUL", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hstd[0] != INVALID_HANDLE_VALUE, "Couldn't create input to NUL\n"); + hstd[1] = CreateFileA("NUL", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hstd[1] != INVALID_HANDLE_VALUE, "Couldn't create input to NUL\n"); + needs_close = TRUE; + break; + case H_PIPE: + ret = CreatePipe(&hstd[0], &hstd[1], NULL, 0); + ok(ret, "Couldn't create anon pipe\n"); + needs_close = TRUE; + break; default: ok(0, "Unsupported handle type %x\n", args & ARG_HANDLE_MASK); return FALSE; @@ -3238,6 +3252,32 @@ static void test_StdHandleInheritance(void) int i, j;
static const struct std_handle_test + nothing_cui[] = + { + /* all others handles type behave as H_DISK */ +/* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + }, + nothing_gui[] = + { + /* testing all types because of discrepancies */ +/* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE, .is_todo = 6}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR}, +/* 5*/ {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_todo = 6}, + {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7}, + }, detached_cui[] = { {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, @@ -3265,6 +3305,8 @@ static void test_StdHandleInheritance(void) tests[] = { #define X(d, cg, s) {(d), (cg), s, ARRAY_SIZE(s), #s} + X(0, TRUE, nothing_cui), + X(0, FALSE, nothing_gui), X(DETACHED_PROCESS, TRUE, detached_cui), X(DETACHED_PROCESS, FALSE, detached_gui), #undef X
From: Eric Pouech epouech@codeweavers.com
The std handles gotten from GetStartupInfo are only set when process was created with STARTD_USESTDHANDLES flag. And yes, 32 (kernel32) and 64 bit (kernelbase) reset the std handles to a different value.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/kernel_main.c | 16 ++++++++++++---- dlls/kernel32/tests/process.c | 22 +++++++++++----------- dlls/kernelbase/process.c | 15 ++++++++++++--- 3 files changed, 35 insertions(+), 18 deletions(-)
diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c index 7b45db73257..da771df1100 100644 --- a/dlls/kernel32/kernel_main.c +++ b/dlls/kernel32/kernel_main.c @@ -108,10 +108,18 @@ static void copy_startup_info(void) startup_infoA.wShowWindow = rupp->wShowWindow; startup_infoA.cbReserved2 = rupp->RuntimeInfo.MaximumLength; startup_infoA.lpReserved2 = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL; - startup_infoA.hStdInput = rupp->hStdInput ? rupp->hStdInput : INVALID_HANDLE_VALUE; - startup_infoA.hStdOutput = rupp->hStdOutput ? rupp->hStdOutput : INVALID_HANDLE_VALUE; - startup_infoA.hStdError = rupp->hStdError ? rupp->hStdError : INVALID_HANDLE_VALUE; - + if (rupp->dwFlags & STARTF_USESTDHANDLES) + { + startup_infoA.hStdInput = rupp->hStdInput; + startup_infoA.hStdOutput = rupp->hStdOutput; + startup_infoA.hStdError = rupp->hStdError; + } + else + { + startup_infoA.hStdInput = INVALID_HANDLE_VALUE; + startup_infoA.hStdOutput = INVALID_HANDLE_VALUE; + startup_infoA.hStdError = INVALID_HANDLE_VALUE; + } RtlReleasePebLock(); }
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 252e1829ab9..56465520569 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -3256,42 +3256,42 @@ static void test_StdHandleInheritance(void) { /* all others handles type behave as H_DISK */ /* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
/* all others handles type behave as H_DISK */ {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, - {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, }, nothing_gui[] = { /* testing all types because of discrepancies */ /* 0*/ {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK, .is_todo = 6}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE}, - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE, .is_todo = 6}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_PIPE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_PIPE}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR}, -/* 5*/ {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_todo = 6}, +/* 5*/ {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CHAR, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 1, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
/* all others handles type behave as H_DISK */ {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, - {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 1}, }, detached_cui[] = { - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_CHAR, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, /* all others handles type behave as H_DISK */ - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, }, detached_gui[] = { - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 4}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, /* all others handles type behave as H_DISK */ - {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 4}, + {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL}, {ARG_STARTUPINFO | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, }; static const struct diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 4807e84594d..860af7e7237 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -1280,9 +1280,18 @@ void init_startup_info( RTL_USER_PROCESS_PARAMETERS *params ) startup_infoW.wShowWindow = params->wShowWindow; startup_infoW.cbReserved2 = params->RuntimeInfo.MaximumLength; startup_infoW.lpReserved2 = params->RuntimeInfo.MaximumLength ? (void *)params->RuntimeInfo.Buffer : NULL; - startup_infoW.hStdInput = params->hStdInput ? params->hStdInput : INVALID_HANDLE_VALUE; - startup_infoW.hStdOutput = params->hStdOutput ? params->hStdOutput : INVALID_HANDLE_VALUE; - startup_infoW.hStdError = params->hStdError ? params->hStdError : INVALID_HANDLE_VALUE; + if (params->dwFlags & STARTF_USESTDHANDLES) + { + startup_infoW.hStdInput = params->hStdInput; + startup_infoW.hStdOutput = params->hStdOutput; + startup_infoW.hStdError = params->hStdError; + } + else + { + startup_infoW.hStdInput = NULL; + startup_infoW.hStdOutput = NULL; + startup_infoW.hStdError = NULL; + }
command_lineW = params->CommandLine.Buffer; if (!RtlUnicodeStringToAnsiString( &ansi, ¶ms->CommandLine, TRUE )) command_lineA = ansi.Buffer;
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/console.c | 12 ++++++------ dlls/kernel32/tests/process.c | 6 +++--- dlls/ntdll/unix/env.c | 24 +++++++++++++++++++++++- include/wine/server_protocol.h | 5 +++-- server/process.c | 4 +++- server/process.h | 1 + server/protocol.def | 1 + server/request.h | 5 +++-- server/trace.c | 1 + 9 files changed, 44 insertions(+), 15 deletions(-)
diff --git a/dlls/kernel32/tests/console.c b/dlls/kernel32/tests/console.c index 54d1a80709b..74f8f467a9f 100644 --- a/dlls/kernel32/tests/console.c +++ b/dlls/kernel32/tests/console.c @@ -5014,10 +5014,10 @@ static void test_CreateProcessCUI(void) {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0}, /* 5*/ {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, 0},
- {FALSE, 0, CONSOLE_STD, 0, TRUE}, + {FALSE, 0, CONSOLE_STD, 0}, {FALSE, DETACHED_PROCESS, CONSOLE_STD, 0}, {FALSE, CREATE_NEW_CONSOLE, CONSOLE_STD, 0}, - {FALSE, CREATE_NO_WINDOW, CONSOLE_STD, 0, TRUE}, + {FALSE, CREATE_NO_WINDOW, CONSOLE_STD, 0}, /*10*/ {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, CONSOLE_STD, 0}, {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, CONSOLE_STD, 0},
@@ -5070,10 +5070,10 @@ static void test_CreateProcessCUI(void) /* 5 */ {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER}, {TRUE, 0, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_ENABLED_CTRLC}, {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER}, - {FALSE, 0, CONSOLE_STD, TRUE, 0, .is_todo = TRUE}, - {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_GROUP_LEADER, .is_todo = TRUE}, -/* 10 */ {FALSE, 0, CONSOLE_STD, FALSE, CP_ENABLED_CTRLC, .is_todo = TRUE}, - {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_GROUP_LEADER, .is_todo = TRUE}, + {FALSE, 0, CONSOLE_STD, TRUE, 0}, + {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_GROUP_LEADER}, +/* 10 */ {FALSE, 0, CONSOLE_STD, FALSE, CP_ENABLED_CTRLC}, + {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_GROUP_LEADER}, {FALSE, 0, STARTUPINFO_STD, TRUE, 0, .is_todo = TRUE}, {FALSE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_GROUP_LEADER, .is_todo = TRUE}, {FALSE, 0, STARTUPINFO_STD, FALSE, CP_ENABLED_CTRLC, .is_todo = TRUE}, diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 56465520569..11cf72c08fa 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -3259,7 +3259,7 @@ static void test_StdHandleInheritance(void) {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK},
/* all others handles type behave as H_DISK */ - {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, }, nothing_gui[] = @@ -3275,8 +3275,8 @@ static void test_StdHandleInheritance(void) {ARG_STD | ARG_CP_INHERIT | ARG_HANDLE_INHERIT | H_CONSOLE, HATTR_NULL, .is_todo = 1, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN},
/* all others handles type behave as H_DISK */ - {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 7, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, - {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_todo = 1}, + {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL}, }, detached_cui[] = { diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 4fd3254b2d2..33b4f20130f 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -2023,6 +2023,26 @@ static RTL_USER_PROCESS_PARAMETERS *build_initial_params( void **module ) }
+static void inherit_std_handles( unsigned int creation_flags, RTL_USER_PROCESS_PARAMETERS *params ) +{ + if (creation_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES) return; + + /* when the inherit flag isn't in CreateProcess by parent, + * only inherit the default std handles for CUI subsystem + */ + if (main_image_info.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI || + (params->dwFlags & STARTF_USESTDHANDLES)) + { + NtClose( params->hStdInput ); + params->hStdInput = NULL; + NtClose( params->hStdOutput ); + params->hStdOutput = NULL; + NtClose( params->hStdError ); + params->hStdError = NULL; + } +} + + /************************************************************************* * init_startup_info */ @@ -2030,7 +2050,7 @@ void init_startup_info(void) { WCHAR *src, *dst, *env, *image; void *module = NULL; - unsigned int status; + unsigned int status, creation_flags; SIZE_T size, info_size, env_size, env_pos; RTL_USER_PROCESS_PARAMETERS *params = NULL; startup_info_t *info; @@ -2050,6 +2070,7 @@ void init_startup_info(void) wine_server_set_reply( req, info, startup_info_size ); status = wine_server_call( req ); machine = reply->machine; + creation_flags = reply->creation_flags; info_size = reply->info_size; env_size = (wine_server_reply_size( reply ) - info_size) / sizeof(WCHAR); } @@ -2139,6 +2160,7 @@ void init_startup_info(void) rebuild_argv(); main_wargv = build_wargv( get_dos_path( image )); free( image ); + inherit_std_handles( creation_flags, params ); init_peb( params, module ); }
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index a392b532f4e..aef56c5dc03 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -954,10 +954,11 @@ struct get_startup_info_reply { struct reply_header __header; data_size_t info_size; + unsigned int creation_flags; unsigned short machine; /* VARARG(info,startup_info,info_size); */ /* VARARG(env,unicode_str); */ - char __pad_14[2]; + char __pad_18[6]; };
@@ -6504,7 +6505,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 784 +#define SERVER_PROTOCOL_VERSION 785
/* ### protocol_version end ### */
diff --git a/server/process.c b/server/process.c index a0d5ea64d97..7039fe27109 100644 --- a/server/process.c +++ b/server/process.c @@ -668,6 +668,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla process->image = NULL; process->job = NULL; process->console = NULL; + process->creation_flags = flags; process->startup_state = STARTUP_IN_PROGRESS; process->startup_info = NULL; process->idle_event = NULL; @@ -1333,7 +1334,7 @@ DECL_HANDLER(new_process) info->data->console = duplicate_handle( parent, info->data->console, process, 0, 0, DUPLICATE_SAME_ACCESS );
- if (!(req->flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES) && info->data->console != 1) + if (!(req->flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES)) { info->data->hstdin = duplicate_handle( parent, info->data->hstdin, process, 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); @@ -1401,6 +1402,7 @@ DECL_HANDLER(get_startup_info)
/* we return the data directly without making a copy so this can only be called once */ reply->machine = process->machine; + reply->creation_flags = process->creation_flags; reply->info_size = info->info_size; size = info->data_size; if (size > get_reply_max_size()) size = get_reply_max_size(); diff --git a/server/process.h b/server/process.h index 97e0d455ece..d564c49933a 100644 --- a/server/process.h +++ b/server/process.h @@ -68,6 +68,7 @@ struct process struct list locks; /* list of file locks owned by the process */ struct list classes; /* window classes owned by the process */ struct console *console; /* console input */ + unsigned int creation_flags; /* flags used by parent to create self */ enum startup_state startup_state; /* startup state */ struct startup_info *startup_info; /* startup info while init is in progress */ struct event *idle_event; /* event for input idle */ diff --git a/server/protocol.def b/server/protocol.def index e9195df6b65..a0606f143fa 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -945,6 +945,7 @@ typedef struct @REQ(get_startup_info) @REPLY data_size_t info_size; /* size of startup info */ + unsigned int creation_flags; /* flags used by parent to create the new process */ unsigned short machine; /* architecture for the new process */ VARARG(info,startup_info,info_size); /* startup information */ VARARG(env,unicode_str); /* environment */ diff --git a/server/request.h b/server/request.h index d6043c5fdc3..9dc38f2a71b 100644 --- a/server/request.h +++ b/server/request.h @@ -772,8 +772,9 @@ C_ASSERT( FIELD_OFFSET(struct new_thread_reply, handle) == 12 ); C_ASSERT( sizeof(struct new_thread_reply) == 16 ); C_ASSERT( sizeof(struct get_startup_info_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_startup_info_reply, info_size) == 8 ); -C_ASSERT( FIELD_OFFSET(struct get_startup_info_reply, machine) == 12 ); -C_ASSERT( sizeof(struct get_startup_info_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_startup_info_reply, creation_flags) == 12 ); +C_ASSERT( FIELD_OFFSET(struct get_startup_info_reply, machine) == 16 ); +C_ASSERT( sizeof(struct get_startup_info_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_request, teb) == 16 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_request, peb) == 24 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_request, ldt_copy) == 32 ); diff --git a/server/trace.c b/server/trace.c index 55ccefa1746..13520183de3 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1447,6 +1447,7 @@ static void dump_get_startup_info_request( const struct get_startup_info_request static void dump_get_startup_info_reply( const struct get_startup_info_reply *req ) { fprintf( stderr, " info_size=%u", req->info_size ); + fprintf( stderr, ", creation_flags=%08x", req->creation_flags ); fprintf( stderr, ", machine=%04x", req->machine ); dump_varargs_startup_info( ", info=", min(cur_size,req->info_size) ); dump_varargs_unicode_str( ", env=", cur_size );
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=140506
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
kernel32: process.c:3215: Test failed: nothing_gui[6] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: nothing_gui[6] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: nothing_gui[7] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: nothing_gui[7] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_cui[0] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_cui[0] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_cui[1] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_cui[1] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_gui[0] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_gui[0] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_gui[1] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_gui[1] : Couldn't set inherit flag to hstd[1]
=== w7u_adm (32 bit report) ===
kernel32: process.c:3215: Test failed: nothing_gui[6] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: nothing_gui[6] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: nothing_gui[7] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: nothing_gui[7] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_cui[0] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_cui[0] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_cui[1] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_cui[1] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_gui[0] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_gui[0] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_gui[1] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_gui[1] : Couldn't set inherit flag to hstd[1]
=== w7u_el (32 bit report) ===
kernel32: process.c:3215: Test failed: nothing_gui[6] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: nothing_gui[6] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: nothing_gui[7] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: nothing_gui[7] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_cui[0] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_cui[0] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_cui[1] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_cui[1] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_gui[0] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_gui[0] : Couldn't set inherit flag to hstd[1] process.c:3215: Test failed: detached_gui[1] : Couldn't set inherit flag to hstd[0] process.c:3217: Test failed: detached_gui[1] : Couldn't set inherit flag to hstd[1]
pushing new version
in this (new) MR:
* tests only covers "good cases" for CreateProcess (the tests for NULL, INVALID_HANDLE, broken std handles will be part of another MR ; should be ok to not throw to much data) * starting to add fixes (need to keep the number of todo:s not too high) (so the title of the MR is a bit off now) * in fourth patch: two comments: * decided not to implement it in server has cui/gui isn't known at the time of child creation, but needed to export whether the handles where inherited or not; decided to expose all the flags for genericity ; could be done otherwise (like using a bit in ConsoleFlags...) * I think the server's test for console_handle being 1 is a leftover from code existing before Jacek's console rewrite * removing Piotr from reviewer (no mode msvcrt adherence; will come back) and added Jacek
for the record:
* mac build failed because of out of space on disk * linux32 failed in threadpool (bug https://bugs.winehq.org/show_bug.cgi?id=55492) * linux64 failed because of COM port. never seen this one.
decided not to implement it in server has cui/gui isn't known at the time of child creation, but needed to export whether the handles where inherited or not; decided to expose all the flags for genericity ; could be done otherwise (like using a bit in ConsoleFlags...)
Could we do that in the parent process? `create_startup_info` knows if child will be GUI or CUI.
I think the server's test for console_handle being 1 is a leftover from code existing before Jacek's console rewrite
Yes, it looks like a leftover. It could be a separated commit.