summaryrefslogtreecommitdiff
path: root/Contrib/SubStart/substart.c
blob: dd03a79b31024d48d19587059734a8222f38ac08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * substart.c - This app runs the executable of the same name in the 'Bin' 
 *              sub-folder and passes along the command line options.
 *
 * Copyright (c) 2013-2018 Anders Kjersem
 *
 * Licensed under the zlib/libpng license (the "License");
 * you may not use this file except in compliance with the License.
 *
 * Licence details can be found in the file COPYING.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.
 */

#include <windows.h>
#include <tchar.h>

#define SUBFOLDER _T("Bin")

/*
 * Leaking things Windows is going to clean up after us anyway avoids 
 * linking to a couple of functions, this saves just enough space 
 * to get the file size down to 2 KiB (MSVC 7.1)
 */
#ifdef _DEBUG
#	define CANLEAK(cod) cod
#else
#	define CANLEAK(cod)
#endif

#define MemFree LocalFree
static void* MemReAlloc(void*OrgMem, size_t cb)
{
	if (!OrgMem) return LocalAlloc(LMEM_FIXED, cb);
	return LocalReAlloc(OrgMem, cb, LMEM_MOVEABLE);
}
static void MemZero(void*pMem, size_t cb)
{
	char*p=(char*)pMem;
	for(; cb;) p[--cb] = 0;
}

static UINT SIOPut(LPCSTR Str, UINT cch)
{
	HANDLE hSO = GetStdHandle(STD_OUTPUT_HANDLE);
	DWORD cbio;
	return WriteFile(hSO, Str, cch, &cbio, 0) ? cch : 0;
}
static UINT SIOFmtPut(LPCSTR Fmt, ...)
{
	UINT cch;
	char buf[150]; // Plenty for our simple strings
	va_list val;
	va_start(val, Fmt);
	cch = wvsprintfA(buf, Fmt, val);
	cch = SIOPut(buf, cch);
	va_end(val);
	return cch;
}

void mainCRTStartup()
{
	const UINT cchSubDir = (sizeof(SUBFOLDER) / sizeof(TCHAR)) - 1;
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	UINT ec, cch, cchParams;
	TCHAR *p = GetCommandLine(), *cmd = 0;

	if (*p == _T('\"'))
		do ++p; while(*p && *p != _T('\"'));
	else
		while(*p && *p > _T(' ')) ++p;

	/* Skip end quote and whitespace */
	do if (!*p) break; else ++p; while(*p <= ' ');

	ec = ERROR_OUTOFMEMORY;
	cchParams = lstrlen(p), cch = MAX_PATH;
	for (;;)
	{
		TCHAR *mem;
		UINT cchTot = 1 + cch + 1 + cchSubDir + 2 + cchParams + 1, cchSelf;
		mem = (TCHAR*) MemReAlloc(cmd, cchTot * sizeof(TCHAR));
		if (!mem) goto app_die;
		cmd = mem;
		cchSelf = GetModuleFileName(NULL, cmd + 1, cch);
		if (!cchSelf) goto app_diegle;
		if (cchSelf < cch)
		{
			/* Insert subfolder before the filename */
			TCHAR *src = cmd + cchSelf + 1, *dst = src + cchSubDir + 1;
			for(; src > cmd; --src, --dst)
			{
				*dst = *src;
				if (_T('\\') == *src || _T('/')  == *src) break;
			}
			*++src = _T('\0');
			lstrcat(src, SUBFOLDER);
			src[cchSubDir] = _T('\\');

			/* Quote path and append parameters */
			cmd[0] = _T('\"');
			lstrcat(cmd, _T("\" "));
			lstrcat(cmd, p);
			break;
		}
		cch *= 2;
	}

	MemZero(&si, sizeof(si));
	si.cb = sizeof(si);

	if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
	{
		DWORD forkec;
		WaitForSingleObject(pi.hProcess, INFINITE);
		GetExitCodeProcess(pi.hProcess, &forkec);
		ec = forkec;
		CANLEAK(CloseHandle(pi.hProcess));
		CANLEAK(CloseHandle(pi.hThread));
		goto app_end;
	}

app_diegle:
	ec = GetLastError();
app_die:
	SIOFmtPut("Unable to start child process, error %#x\n", ec);
app_end:
	CANLEAK(MemFree(cmd));
	ExitProcess(ec);
}