From 4b3a146fdd2606e9ab132ca858d43330548be66e Mon Sep 17 00:00:00 2001 From: anders_k Date: Sun, 23 Jun 2013 15:07:57 +0000 Subject: [PATCH] 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 --- Contrib/SubStart/ReadMe.txt | 34 ------ Contrib/SubStart/SConscript | 4 +- Contrib/SubStart/substart.c | 202 ++++++++++++++++++++---------------- 3 files changed, 114 insertions(+), 126 deletions(-) delete mode 100644 Contrib/SubStart/ReadMe.txt diff --git a/Contrib/SubStart/ReadMe.txt b/Contrib/SubStart/ReadMe.txt deleted file mode 100644 index bbb12e32..00000000 --- a/Contrib/SubStart/ReadMe.txt +++ /dev/null @@ -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. - diff --git a/Contrib/SubStart/SConscript b/Contrib/SubStart/SConscript index c125305c..70b17ed8 100644 --- a/Contrib/SubStart/SConscript +++ b/Contrib/SubStart/SConscript @@ -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 diff --git a/Contrib/SubStart/substart.c b/Contrib/SubStart/substart.c index 92134811..8e226f75 100644 --- a/Contrib/SubStart/substart.c +++ b/Contrib/SubStart/substart.c @@ -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 #include -#include -/* 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); +}