- version information consolidated into version.h - removed strip from Makefile - updated PKGBUILD - fixed minor things in launcher.c - added header guards
230 lines
5.1 KiB
C
230 lines
5.1 KiB
C
#define _UNICODE
|
|
#define _WIN32_WINNT 0x0601
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define PSAPI_VERSION 1
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <wchar.h>
|
|
|
|
#include "macros.h"
|
|
|
|
// if any of the properties change, it's best to use a brand new AppID
|
|
#define APPID_REVISION 9
|
|
|
|
static void ShowError(const wchar_t* desc, const wchar_t* err, const long code) {
|
|
wchar_t msg[1024];
|
|
|
|
swprintf(msg, 1024, L"%s. Reason: %s (0x%lx)", desc, err, code);
|
|
MessageBox(NULL, msg, L"Launcher error", MB_ICONEXCLAMATION | MB_OK);
|
|
}
|
|
|
|
static void ShowLastError(const wchar_t* desc) {
|
|
DWORD code;
|
|
wchar_t* err;
|
|
|
|
code = GetLastError();
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&err, 0, NULL);
|
|
ShowError(desc, err, code);
|
|
LocalFree(err);
|
|
}
|
|
|
|
static void ShowErrno(const wchar_t* desc) {
|
|
wchar_t* err;
|
|
|
|
err = _wcserror(errno);
|
|
ShowError(desc, err, errno);
|
|
}
|
|
|
|
static PROCESS_INFORMATION StartChild(wchar_t* cmdline) {
|
|
STARTUPINFOW si;
|
|
PROCESS_INFORMATION pi;
|
|
DWORD code;
|
|
|
|
ZeroMemory(&si, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
ZeroMemory(&pi, sizeof(pi));
|
|
SetLastError(0);
|
|
code = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
|
|
if (code == 0) {
|
|
ShowLastError(L"Could not start the shell");
|
|
ShowError(L"The command was", cmdline, 0);
|
|
return pi;
|
|
}
|
|
|
|
return pi;
|
|
}
|
|
|
|
static wchar_t* SetEnv(wchar_t* conffile) {
|
|
int code;
|
|
size_t buflen;
|
|
wchar_t* tmp;
|
|
wchar_t* buf;
|
|
wchar_t* msystem;
|
|
FILE* handle;
|
|
|
|
msystem = NULL;
|
|
|
|
handle = _wfopen(conffile, L"rt");
|
|
if (handle == NULL) {
|
|
ShowErrno(L"Could not open configuration file");
|
|
return msystem;
|
|
}
|
|
|
|
buflen = 512;
|
|
buf = (wchar_t*)malloc(buflen * sizeof(wchar_t));
|
|
*buf = L'\0';
|
|
while (true) {
|
|
tmp = fgetws(buf + wcslen(buf), buflen - wcslen(buf), handle);
|
|
if (tmp == NULL && !feof(handle)) {
|
|
ShowErrno(L"Could not read from configuration file");
|
|
return NULL;
|
|
}
|
|
|
|
tmp = buf + wcslen(buf) - 1;
|
|
if (!feof(handle) && *tmp != L'\n') {
|
|
buflen *= 2;
|
|
buf = (wchar_t*)realloc(buf, buflen * sizeof(wchar_t));
|
|
continue;
|
|
}
|
|
if (!feof(handle)) {
|
|
*tmp = L'\0';
|
|
}
|
|
|
|
if (*buf != L'\0' && *buf != L'#') {
|
|
tmp = wcschr(buf, L'=');
|
|
if (tmp != NULL) {
|
|
*tmp = L'\0';
|
|
if (0 == wcscmp(L"MSYSTEM", buf)) {
|
|
msystem = _wcsdup(tmp + 1);
|
|
if (msystem == NULL) {
|
|
ShowError(L"Could not duplicate string", buf, 0);
|
|
return NULL;
|
|
}
|
|
}
|
|
code = SetEnvironmentVariable(buf, tmp + 1);
|
|
if (code == 0) {
|
|
ShowLastError(L"Could not set environment variable");
|
|
}
|
|
} else {
|
|
ShowError(L"Could not parse environment line", buf, 0);
|
|
}
|
|
}
|
|
|
|
*buf = L'\0';
|
|
if (feof(handle)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
code = fclose(handle);
|
|
if (code != 0) {
|
|
ShowErrno(L"Could not close configuration file");
|
|
}
|
|
|
|
return msystem;
|
|
}
|
|
|
|
int wmain(int argc, wchar_t* argv[]) {
|
|
PROCESS_INFORMATION child;
|
|
int code;
|
|
size_t buflen;
|
|
wchar_t* buf;
|
|
wchar_t* tmp;
|
|
wchar_t* args;
|
|
wchar_t* msystem;
|
|
wchar_t msysdir[PATH_MAX];
|
|
wchar_t exepath[PATH_MAX];
|
|
wchar_t confpath[PATH_MAX];
|
|
|
|
code = GetModuleFileName(NULL, exepath, sizeof(exepath) / sizeof(exepath[0]));
|
|
if (code == 0) {
|
|
ShowLastError(L"Could not determine executable path");
|
|
return __LINE__;
|
|
}
|
|
|
|
tmp = exepath;
|
|
while (true) {
|
|
tmp = wcschr(tmp, L'/');
|
|
if (tmp == NULL) {
|
|
break;
|
|
}
|
|
*tmp = L'\\';
|
|
}
|
|
|
|
wcscpy(msysdir, exepath);
|
|
tmp = wcsrchr(msysdir, L'\\');
|
|
if (tmp == NULL) {
|
|
ShowError(L"Could not find root directory", msysdir, 0);
|
|
return __LINE__;
|
|
}
|
|
*tmp = L'\0';
|
|
|
|
wcscpy(confpath, exepath);
|
|
tmp = confpath + wcslen(confpath) - 4;
|
|
if (0 != wcsicmp(L".exe", tmp)) {
|
|
ShowError(L"Could not find configuration file", confpath, 0);
|
|
return __LINE__;
|
|
}
|
|
*tmp++ = L'.';
|
|
*tmp++ = L'i';
|
|
*tmp++ = L'n';
|
|
*tmp++ = L'i';
|
|
|
|
if (argc > 1) {
|
|
code = SetEnvironmentVariable(L"CHERE_INVOKING", L"1");
|
|
if (code == 0) {
|
|
ShowLastError(L"Could not set environment variable");
|
|
}
|
|
}
|
|
|
|
msystem = SetEnv(confpath);
|
|
if (msystem == NULL) {
|
|
ShowError(L"Did not find the MSYSTEM variable", confpath, 0);
|
|
return __LINE__;
|
|
}
|
|
|
|
code = SetEnvironmentVariable(L"MSYSCON", L"mintty.exe");
|
|
if (code == 0) {
|
|
ShowLastError(L"Could not set environment variable");
|
|
}
|
|
|
|
// can break, but hopefully won't for most use cases
|
|
args = GetCommandLine();
|
|
if (args[0] == L'"') {
|
|
args++;
|
|
}
|
|
args += wcslen(argv[0]);
|
|
if (args[0] == L'"') {
|
|
args++;
|
|
}
|
|
|
|
code = -1;
|
|
buf = NULL;
|
|
buflen = 1024;
|
|
while (code < 0 && buflen < 8192) {
|
|
buf = (wchar_t*)realloc(buf, buflen * sizeof(wchar_t));
|
|
if (buf == NULL) {
|
|
ShowError(L"Could not allocate memory", L"", 0);
|
|
return __LINE__;
|
|
}
|
|
code = swprintf(buf, buflen, L"%s\\usr\\bin\\mintty.exe -i '%s' -o 'AppLaunchCmd=%s' -o 'AppID=MSYS2.Shell.%s.%d' -o 'AppName=MSYS2 %s Shell' --store-taskbar-properties -- /usr/bin/bash --login %s %s", msysdir, exepath, exepath, msystem, APPID_REVISION, msystem, argc == 1 ? L"-i" : L"-c '$0 \"$@\"'", args);
|
|
buflen *= 2;
|
|
}
|
|
if (code < 0) {
|
|
ShowErrno(L"Could not write to buffer");
|
|
return __LINE__;
|
|
}
|
|
|
|
child = StartChild(buf);
|
|
if (child.hProcess == NULL) {
|
|
return __LINE__;
|
|
}
|
|
|
|
free(buf);
|
|
buf = NULL;
|
|
|
|
return 0;
|
|
}
|