From 948dc5fbc3dc51f9698daa1e097af51bb9314834 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 4 May 2015 03:18:20 -0700 Subject: [PATCH] git wrapper: allow _Git Bash_ to run with a newly allocated console With a recent change in Cygwin (which is the basis of the msys2-runtime), a GUI process desiring to launch an MSys2 executable needs to allocate a console for the new process (otherwise the process will just hang on Windows XP). _Git Bash_ is such a GUI process. While at it, use correct handles when inheriting the stdin/stdout/stderr handles: `GetStdHandle()` returns NULL for invalid handles, but the STARTUPINFO must specify `INVALID_HANDLE_VALUE` instead. Originally, the hope was that only this `NULL` => `INVALID_HANDLE_VALUE` conversion would be required to fix the Windows XP issue mentioned above (extensive debugging revealed that starting _Git Bash_ on Windows XP would yield invalid handles for `stdin` and `stderr`, but *not* for `stdout`). However, while _Git Bash_ eventually showed a `mintty` when not allocating a new console, it took around one second to show it, and several seconds to close it. So let's just include both fixes. Signed-off-by: Johannes Schindelin --- compat/win32/git-wrapper.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/compat/win32/git-wrapper.c b/compat/win32/git-wrapper.c index 20e8936eef..d57095a605 100644 --- a/compat/win32/git-wrapper.c +++ b/compat/win32/git-wrapper.c @@ -187,9 +187,9 @@ static int strip_prefix(LPWSTR str, int *len, LPCWSTR prefix) static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, LPWSTR *prefix_args, int *prefix_args_len, int *is_git_command, LPWSTR *working_directory, int *full_path, - int *skip_arguments) + int *skip_arguments, int *allocate_console) { - int id, minimal_search_path, wargc; + int id, minimal_search_path, needs_a_console, wargc; LPWSTR *wargv; #define BUFSIZE 65536 @@ -198,6 +198,7 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, for (id = 0; ; id++) { minimal_search_path = 0; + needs_a_console = 0; len = LoadString(NULL, id, buf, BUFSIZE); if (!len) { @@ -218,6 +219,8 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, for (;;) { if (strip_prefix(buf, &len, L"MINIMAL_PATH=1 ")) minimal_search_path = 1; + else if (strip_prefix(buf, &len, L"ALLOC_CONSOLE=1 ")) + needs_a_console = 1; else break; } @@ -298,6 +301,8 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, } if (minimal_search_path) *full_path = 0; + if (needs_a_console) + *allocate_console = 1; LocalFree(wargv); return 1; @@ -306,7 +311,8 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep, int main(void) { int r = 1, wait = 1, prefix_args_len = -1, needs_env_setup = 1, - is_git_command = 1, full_path = 1, skip_arguments = 0; + is_git_command = 1, full_path = 1, skip_arguments = 0, + allocate_console = 0; WCHAR exepath[MAX_PATH], exe[MAX_PATH]; LPWSTR cmd = NULL, exep = exe, prefix_args = NULL, basename; LPWSTR working_directory = NULL; @@ -326,11 +332,12 @@ int main(void) if (configure_via_resource(basename, exepath, exep, &prefix_args, &prefix_args_len, &is_git_command, &working_directory, - &full_path, &skip_arguments)) { + &full_path, &skip_arguments, &allocate_console)) { /* do nothing */ } else if (!wcsicmp(basename, L"git-gui.exe")) { static WCHAR buffer[BUFSIZE]; + allocate_console = 1; if (!PathRemoveFileSpec(exepath)) { fwprintf(stderr, L"Invalid executable path: %s\n", exepath); @@ -386,6 +393,7 @@ int main(void) } else if (!wcsicmp(basename, L"gitk.exe")) { static WCHAR buffer[BUFSIZE]; + allocate_console = 1; if (!PathRemoveFileSpec(exepath)) { fwprintf(stderr, L"Invalid executable path: %s\n", exepath); @@ -437,16 +445,20 @@ int main(void) ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); - console_handle = CreateFile(L"CONOUT$", GENERIC_WRITE, + if (allocate_console) + creation_flags |= CREATE_NEW_CONSOLE; + else if ((console_handle = CreateFile(L"CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (console_handle != INVALID_HANDLE_VALUE) + FILE_ATTRIBUTE_NORMAL, NULL)) != + INVALID_HANDLE_VALUE) CloseHandle(console_handle); else { +#define STD_HANDLE(field, id) si.hStd##field = GetStdHandle(STD_##id); if (!si.hStd##field) si.hStd##field = INVALID_HANDLE_VALUE + STD_HANDLE(Input, INPUT_HANDLE); + STD_HANDLE(Output, OUTPUT_HANDLE); + STD_HANDLE(Error, ERROR_HANDLE); si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + creation_flags |= CREATE_NO_WINDOW; } @@ -455,7 +467,8 @@ int main(void) cmd, /* modified command line */ NULL, /* process handle inheritance */ NULL, /* thread handle inheritance */ - TRUE, /* handles inheritable? */ + /* handles inheritable? */ + allocate_console ? FALSE : TRUE, creation_flags, NULL, /* environment: use parent */ working_directory, /* use parent's */