Rewrote SubStart, does not use CRT

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6377 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2013-06-23 15:07:57 +00:00
parent e6f549adee
commit 4b3a146fdd
3 changed files with 114 additions and 126 deletions

View file

@ -1,7 +1,8 @@
/*
* substart.c
* 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) 2010 Thomas Gaugler
* Copyright (c) 2013 Anders Kjersem
*
* Licensed under the zlib/libpng license (the "License");
* you may not use this file except in compliance with the License.
@ -14,99 +15,118 @@
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
/* Macro to determine the string length of a constant */
#define CONST_STRLEN(x) ((sizeof(x) / sizeof(*x)) - 1)
#define SUBFOLDER _T("Bin")
/* Name of the sub folder containing the executable
invoked by this stub executable.
/*
* 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)
*/
static const TCHAR SUBFOLDER[] = _T("Bin");
#ifdef _DEBUG
# define CANLEAK(cod) cod
#else
# define CANLEAK(cod)
#endif
/* Redirect to an executable located in a sub folder relative to
this starter executable. Name of the stub executable has to
match with the one in the sub folder.
The command line parameters are passed along.
*/
int main( int argc, char *argv[] )
#define MemFree LocalFree
static void* MemReAlloc(void*OrgMem, size_t cb)
{
int err = ERROR_SUCCESS;
TCHAR szPath[MAX_PATH];
/* Get the full path of the running executable */
if ( GetModuleFileName( NULL, szPath, MAX_PATH ) )
{
size_t len = _tcslen(szPath);
size_t offset = len + CONST_STRLEN(SUBFOLDER) + 1;
err = ERROR_BAD_PATHNAME;
if (offset < MAX_PATH)
{
/* Move file name part of full path by length of sub folder
name and thereafter fill in the sub folder name in the
newly created gap.
*/
register TCHAR *p = szPath + len;
register TCHAR *q = szPath + offset;
while (p > szPath)
{
*(q--) = *(p--);
if (*p == '\\')
{
/* Fill in sub folder name */
*q = *p;
q = ++p;
p = (TCHAR *)SUBFOLDER;
while (*p)
{
*(q++) = *(p++);
}
err = ERROR_SUCCESS;
break;
}
}
}
if (err)
{
_tprintf( _T("Path too long: %s\n"), szPath );
}
else
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
/* Start and wait for a process with the same filename as
ourself located in SUBFOLDER.
WARNING: The subprocess can't parse GetCommandLine()
to find its own path since we pass the wrong path! */
if ( CreateProcess( szPath, GetCommandLine(), NULL, NULL,
TRUE, 0, NULL, NULL, &si, &pi ) )
{
WaitForSingleObject( pi.hProcess, INFINITE );
GetExitCodeProcess( pi.hProcess, (DWORD*) &err );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
else
{
err = GetLastError();
_tprintf( _T("CreateProcess (%s) failed (%d).\n"), szPath, err );
}
}
}
else
{
err = GetLastError();
_tprintf( _T("GetModuleFileName failed (%d).\n"), err );
}
return err;
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);
}