パソコンでプログラミングしよう ウィンドウズC++プログラミング環境の構築
1.6.3.6(15)
ソースコード(git.exeラッパー)

git.exeラッパーが適切に環境変数PATHなどを設定する事をソースコードで確認する。

ダウンロードリンク

msysGit時代の古いソースコードしか発見できずこれで代用した。PATH追加にmingw\binがあるが現在のGit for Windowsではmingw32\binあるいはmingw64\binであるはずだ。

ソースコード

/*
* git-wrapper - replace cmd\git.cmd with an executable
*
* Copyright (C) 2012 Pat Thoyts <patthoyts@users.sourceforge.net>
*/
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <shlwapi.h>
#include <shellapi.h>
#include <stdio.h>
static void
PrintError(LPCWSTR wszPrefix, DWORD dwError)
{
LPWSTR lpsz = NULL;
DWORD cch = 0;
cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwError, LANG_NEUTRAL,
(LPTSTR)&lpsz, 0, NULL);
if (cch < 1) {
cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
L"Code 0x%1!08x!",
0, LANG_NEUTRAL, (LPTSTR)&lpsz, 0,
(va_list*)&dwError);
}
fwprintf(stderr, L"%s: %s", wszPrefix, lpsz);
LocalFree((HLOCAL)lpsz);
}
int
main(void)
{
int r = 1, wait = 1;
WCHAR exepath[MAX_PATH], exe[MAX_PATH];
LPWSTR cmd = NULL, path2 = NULL, exep = exe;
UINT codepage = 0;
int len;
/* get the installation location */
GetModuleFileName(NULL, exepath, MAX_PATH);
PathRemoveFileSpec(exepath);
PathRemoveFileSpec(exepath);
/* set the default exe module */
wcscpy(exe, exepath);
PathAppend(exe, L"bin\\git.exe");
/* if not set, set TERM to msys */
if (GetEnvironmentVariable(L"TERM", NULL, 0) == 0) {
SetEnvironmentVariable(L"TERM", L"msys");
}
/* if not set, set PLINK_PROTOCOL to ssh */
if (GetEnvironmentVariable(L"PLINK_PROTOCOL", NULL, 0) == 0) {
SetEnvironmentVariable(L"PLINK_PROTOCOL", L"ssh");
}
/* set HOME to %HOMEDRIVE%%HOMEPATH% or %USERPROFILE%
* With roaming profiles: HOMEPATH is the roaming location and
* USERPROFILE is the local location
*/
if (GetEnvironmentVariable(L"HOME", NULL, 0) == 0) {
LPWSTR e = NULL;
len = GetEnvironmentVariable(L"HOMEPATH", NULL, 0);
if (len == 0) {
len = GetEnvironmentVariable(L"USERPROFILE", NULL, 0);
if (len != 0) {
e = (LPWSTR)malloc(len * sizeof(WCHAR));
GetEnvironmentVariable(L"USERPROFILE", e, len);
SetEnvironmentVariable(L"HOME", e);
free(e);
}
} else {
int n;
len += GetEnvironmentVariable(L"HOMEDRIVE", NULL, 0);
e = (LPWSTR)malloc(sizeof(WCHAR) * (len + 2));
n = GetEnvironmentVariable(L"HOMEDRIVE", e, len);
GetEnvironmentVariable(L"HOMEPATH", &e[n], len-n);
SetEnvironmentVariable(L"HOME", e);
free(e);
}
}
/* extend the PATH */
len = GetEnvironmentVariable(L"PATH", NULL, 0);
len = sizeof(WCHAR) * (len + 2 * MAX_PATH);
path2 = (LPWSTR)malloc(len);
wcscpy(path2, exepath);
PathAppend(path2, L"bin;");
/* should do this only if it exists */
wcscat(path2, exepath);
PathAppend(path2, L"mingw\\bin;");
GetEnvironmentVariable(L"PATH", &path2[wcslen(path2)],
(len/sizeof(WCHAR))-wcslen(path2));
SetEnvironmentVariable(L"PATH", path2);
free(path2);
/* fix up the command line to call git.exe
* We have to be very careful about quoting here so we just
* trim off the first argument and replace it leaving the rest
* untouched.
*/
{
int wargc = 0, gui = 0;
LPWSTR cmdline = NULL;
LPWSTR *wargv = NULL, p = NULL;
cmdline = GetCommandLine();
wargv = CommandLineToArgvW(cmdline, &wargc);
cmd = (LPWSTR)malloc(sizeof(WCHAR) * (wcslen(cmdline) + MAX_PATH));
if (wargc > 1 && wcsicmp(L"gui", wargv[1]) == 0) {
wait = 0;
if (wargc > 2 && wcsicmp(L"citool", wargv[2]) == 0) {
wait = 1;
wcscpy(cmd, L"git.exe");
} else {
WCHAR script[MAX_PATH];
gui = 1;
wcscpy(script, exepath);
PathAppend(script, L"libexec\\git-core\\git-gui");
PathQuoteSpaces(script);
wcscpy(cmd, L"wish.exe ");
wcscat(cmd, script);
wcscat(cmd, L" --");
exep = NULL; /* find the module from the commandline */
}
} else {
wcscpy(cmd, L"git.exe");
}
/* find the first space after the initial parameter then append all */
p = wcschr(&cmdline[wcslen(wargv[0])], L' ');
if (p && *p) {
/* for git gui subcommands, remove the 'gui' word */
if (gui) {
while (*p == L' ') ++p;
p = wcschr(p, L' ');
}
if (p && *p)
wcscat(cmd, p);
}
LocalFree(wargv);
}
/* set the console to ANSI/GUI codepage */
codepage = GetConsoleCP();
SetConsoleCP(GetACP());
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL br = FALSE;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
br = CreateProcess(exep,/* module: null means use command line */
cmd, /* modified command line */
NULL, /* process handle inheritance */
NULL, /* thread handle inheritance */
TRUE, /* handles inheritable? */
CREATE_UNICODE_ENVIRONMENT,
NULL, /* environment: use parent */
NULL, /* starting directory: use parent */
&si, &pi);
if (br) {
if (wait)
WaitForSingleObject(pi.hProcess, INFINITE);
if (!GetExitCodeProcess(pi.hProcess, (DWORD *)&r))
PrintError(L"error reading exit code", GetLastError());
CloseHandle(pi.hProcess);
} else {
PrintError(L"error launching git", GetLastError());
r = 1;
}
}
free(cmd);
/* reset the console codepage */
SetConsoleCP(codepage);
ExitProcess(r);
}
/*
* Local variables:
* mode: c
* indent-tabs-mode: nil
* c-basic-offset: 4
* tab-width: 4
* End:
*/

説明

ウィンドウズAPIで構成されたシンプルなソースコードと言える。Git for WindowsはC:\Program Files\Gitにインストールされていて、ユーザーディレクトリはC:\Users\userとする。設定する環境変数をまとめる。

環境変数 備考
TERM msys
PLINK_PROTOCOL ssh
HOME C:\Users\user %HOMEDRIVE%%HOMEPATH%あるいは%USERPROFILE%
PATH C:\Program Files\Git\mingw\bin;%PATH% mingwはmingw32/mingw64のいずれか

この環境の下にディレクトリパスを含まない"git.exe"がウィンドウズAPIのCreateProcess関数で起動される。