2 * headless Git - run Git without opening a console window on Windows
6 #define WIN32_LEAN_AND_MEAN
15 * If `dir` contains the path to a Git exec directory, extend `PATH` to
16 * include the corresponding `bin/` directory (which is where all those
17 * `.dll` files needed by `git.exe` are, on Windows).
19 static int extend_path(wchar_t *dir
, size_t dir_len
)
21 const wchar_t *suffix
= L
"\\libexec\\git-core";
22 size_t suffix_len
= wcslen(suffix
);
26 if (dir_len
< suffix_len
)
29 dir_len
-= suffix_len
;
30 if (memcmp(dir
+ dir_len
, suffix
, suffix_len
* sizeof(wchar_t)))
33 len
= GetEnvironmentVariableW(L
"PATH", NULL
, 0);
37 env
= _alloca((dir_len
+ 5 + len
) * sizeof(wchar_t));
38 wcsncpy(env
, dir
, dir_len
);
39 wcscpy(env
+ dir_len
, L
"\\bin;");
40 if (!GetEnvironmentVariableW(L
"PATH", env
+ dir_len
+ 5, len
))
43 SetEnvironmentVariableW(L
"PATH", env
);
47 int WINAPI
wWinMain(_In_ HINSTANCE instance
,
48 _In_opt_ HINSTANCE previous_instance
,
49 _In_ LPWSTR command_line
, _In_
int show
)
51 wchar_t git_command_line
[32768];
52 size_t size
= sizeof(git_command_line
) / sizeof(wchar_t);
53 const wchar_t *needs_quotes
= L
"";
56 STARTUPINFO startup_info
= {
57 .cb
= sizeof(STARTUPINFO
),
58 .dwFlags
= STARTF_USESHOWWINDOW
,
59 .wShowWindow
= SW_HIDE
,
61 PROCESS_INFORMATION process_info
= { 0 };
62 DWORD creation_flags
= CREATE_UNICODE_ENVIRONMENT
|
63 CREATE_NEW_CONSOLE
| CREATE_NO_WINDOW
;
66 /* First, determine the full path of argv[0] */
67 for (i
= 0; _wpgmptr
[i
]; i
++)
68 if (_wpgmptr
[i
] == L
' ')
70 else if (_wpgmptr
[i
] == L
'\\')
73 if (slash
>= size
- 11)
74 return 127; /* Too long path */
76 /* If it is in Git's exec path, add the bin/ directory to the PATH */
77 extend_path(_wpgmptr
, slash
);
79 /* Then, add the full path of `git.exe` as argv[0] */
80 i
= swprintf_s(git_command_line
, size
, L
"%ls%.*ls\\git.exe%ls",
81 needs_quotes
, slash
, _wpgmptr
, needs_quotes
);
83 return 127; /* Too long path */
86 /* Now, append the command-line arguments */
87 i
= swprintf_s(git_command_line
+ i
, size
- i
,
88 L
" %ls", command_line
);
93 startup_info
.hStdInput
= GetStdHandle(STD_INPUT_HANDLE
);
94 startup_info
.hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
95 startup_info
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
97 if (!CreateProcess(NULL
, /* infer argv[0] from the command line */
98 git_command_line
, /* modified command line */
99 NULL
, /* inherit process handles? */
100 NULL
, /* inherit thread handles? */
101 FALSE
, /* handles inheritable? */
103 NULL
, /* use this process' environment */
104 NULL
, /* use this process' working directory */
105 &startup_info
, &process_info
))
106 return 129; /* could not start */
107 WaitForSingleObject(process_info
.hProcess
, INFINITE
);
108 if (!GetExitCodeProcess(process_info
.hProcess
, &exit_code
))
109 exit_code
= 130; /* Could not determine exit code? */
111 CloseHandle(process_info
.hProcess
);
112 CloseHandle(process_info
.hThread
);
114 return (int)exit_code
;