116 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
| /*
 | |
|  * headless Git - run Git without opening a console window on Windows
 | |
|  */
 | |
| 
 | |
| #define STRICT
 | |
| #define WIN32_LEAN_AND_MEAN
 | |
| #define UNICODE
 | |
| #define _UNICODE
 | |
| #include <windows.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <wchar.h>
 | |
| 
 | |
| /*
 | |
|  * If `dir` contains the path to a Git exec directory, extend `PATH` to
 | |
|  * include the corresponding `bin/` directory (which is where all those
 | |
|  * `.dll` files needed by `git.exe` are, on Windows).
 | |
|  */
 | |
| static int extend_path(wchar_t *dir, size_t dir_len)
 | |
| {
 | |
| 	const wchar_t *suffix = L"\\libexec\\git-core";
 | |
| 	size_t suffix_len = wcslen(suffix);
 | |
| 	wchar_t *env;
 | |
| 	DWORD len;
 | |
| 
 | |
| 	if (dir_len < suffix_len)
 | |
| 		return 0;
 | |
| 
 | |
| 	dir_len -= suffix_len;
 | |
| 	if (memcmp(dir + dir_len, suffix, suffix_len * sizeof(wchar_t)))
 | |
| 		return 0;
 | |
| 
 | |
| 	len = GetEnvironmentVariableW(L"PATH", NULL, 0);
 | |
| 	if (!len)
 | |
| 		return 0;
 | |
| 
 | |
| 	env = _alloca((dir_len + 5 + len) * sizeof(wchar_t));
 | |
| 	wcsncpy(env, dir, dir_len);
 | |
| 	wcscpy(env + dir_len, L"\\bin;");
 | |
| 	if (!GetEnvironmentVariableW(L"PATH", env + dir_len + 5, len))
 | |
| 		return 0;
 | |
| 
 | |
| 	SetEnvironmentVariableW(L"PATH", env);
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int WINAPI wWinMain(_In_ HINSTANCE instance,
 | |
| 		    _In_opt_ HINSTANCE previous_instance,
 | |
| 		    _In_ LPWSTR command_line, _In_ int show)
 | |
| {
 | |
| 	wchar_t git_command_line[32768];
 | |
| 	size_t size = sizeof(git_command_line) / sizeof(wchar_t);
 | |
| 	const wchar_t *needs_quotes = L"";
 | |
| 	int slash = 0, i;
 | |
| 
 | |
| 	STARTUPINFO startup_info = {
 | |
| 		.cb = sizeof(STARTUPINFO),
 | |
| 		.dwFlags = STARTF_USESHOWWINDOW,
 | |
| 		.wShowWindow = SW_HIDE,
 | |
| 	};
 | |
| 	PROCESS_INFORMATION process_info = { 0 };
 | |
| 	DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT |
 | |
| 		CREATE_NEW_CONSOLE | CREATE_NO_WINDOW;
 | |
| 	DWORD exit_code;
 | |
| 
 | |
| 	/* First, determine the full path of argv[0] */
 | |
| 	for (i = 0; _wpgmptr[i]; i++)
 | |
| 		if (_wpgmptr[i] == L' ')
 | |
| 			needs_quotes = L"\"";
 | |
| 		else if (_wpgmptr[i] == L'\\')
 | |
| 			slash = i;
 | |
| 
 | |
| 	if (slash >= size - 11)
 | |
| 		return 127; /* Too long path */
 | |
| 
 | |
| 	/* If it is in Git's exec path, add the bin/ directory to the PATH */
 | |
| 	extend_path(_wpgmptr, slash);
 | |
| 
 | |
| 	/* Then, add the full path of `git.exe` as argv[0] */
 | |
| 	i = swprintf_s(git_command_line, size, L"%ls%.*ls\\git.exe%ls",
 | |
| 		       needs_quotes, slash, _wpgmptr, needs_quotes);
 | |
| 	if (i < 0)
 | |
| 		return 127; /* Too long path */
 | |
| 
 | |
| 	if (*command_line) {
 | |
| 		/* Now, append the command-line arguments */
 | |
| 		i = swprintf_s(git_command_line + i, size - i,
 | |
| 			       L" %ls", command_line);
 | |
| 		if (i < 0)
 | |
| 			return 127;
 | |
| 	}
 | |
| 
 | |
| 	startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
 | |
| 	startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 | |
| 	startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
 | |
| 
 | |
| 	if (!CreateProcess(NULL, /* infer argv[0] from the command line */
 | |
| 			   git_command_line, /* modified command line */
 | |
| 			   NULL, /* inherit process handles? */
 | |
| 			   NULL, /* inherit thread handles? */
 | |
| 			   FALSE, /* handles inheritable? */
 | |
| 			   creation_flags,
 | |
| 			   NULL, /* use this process' environment */
 | |
| 			   NULL, /* use this process' working directory */
 | |
| 			   &startup_info, &process_info))
 | |
| 		return 129; /* could not start */
 | |
| 	WaitForSingleObject(process_info.hProcess, INFINITE);
 | |
| 	if (!GetExitCodeProcess(process_info.hProcess, &exit_code))
 | |
| 		exit_code = 130; /* Could not determine exit code? */
 | |
| 
 | |
| 	CloseHandle(process_info.hProcess);
 | |
| 	CloseHandle(process_info.hThread);
 | |
| 
 | |
| 	return (int)exit_code;
 | |
| }
 |