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,34 +0,0 @@
substart - Redirect to an executable located in the 'Bin' sub folder
relative to the starter executable.
------------------------------------------------------------------------
Copyright (C) 2010 Thomas Gaugler
Licensed under the zlib/libpng license
This tool runs the executable of the same name in the 'Bin' sub folder
and passes along the command line options.
The main purpose of the tool is that scripts expecting an executable in
the root of the program installation folder continue to run.
USAGE
-----
The original executable has to go into the 'Bin' sub folder and the
the substart executable renamed to the original executable name needs
to be placed at the original location.
EXAMPLE
-------
Directory hierarchy:
C:\Program Files\NSIS
C:\Program Files\NSIS\Bin\makensis.exe
C:\Program Files\NSIS\makensis.exe (-> substart.exe renamed to makensis.exe)
C:\Program Files\NSIS\makensis.exe /VERSION
Please be aware that the name of the substart executable has to match
with the one in the sub folder.

View file

@ -7,10 +7,12 @@ files = Split("""
""")
libs = Split("""
kernel32
user32
""")
Import('BuildUtil')
substart = BuildUtil(target, files, libs, cli = True, noinstall = True)
substart = BuildUtil(target, files, libs, cli = True, noinstall = True, nodeflib = True)
env.DistributeBin(substart, names=['makensis.exe'], alias='install-compiler') # install as makensis

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);
}