NSIS/Source/exehead/Main.c
anders_k 7cc150c464 MakeNSIS can now generate Unicode or Ansi installers based on a script attribute. SCons generates both Ansi and Unicode stubs and plugins.
The official plugins are now stored in architecture specific subdirectories under NSIS\Plugins. !AddPluginDir also gained a new (optional) architecture flag because MakeNSIS now stores separate plugin information for each target architecture. Storing plugins in the root of the Plugins directory is no longer supported.

MinGW does not implement the unicode CRT startup functions so the entry point functions and linker parameters had to be changed. The unicode tools use the ansi entry point and a small helper function that calls into the real code: _tmain has full argc+argv emulation while wWinMain does not pass the command line parameters. The stubs do not use any CRT functions and have no CRT or unicode helper code, they call our entry point directly.



git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6269 212acab6-be3b-0410-9dea-997c60f758d6
2012-10-13 01:47:50 +00:00

366 lines
10 KiB
C

/*
* main.c: executable header main code
*
* This file is a part of NSIS.
*
* Copyright (C) 1999-2009 Nullsoft and Contributors
*
* 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.
*
* Unicode support by Jim Park -- 08/22/2007
*/
#include "../Platform.h"
#include <shlobj.h>
#include "resource.h"
#include "util.h"
#include "fileform.h"
#include "state.h"
#include "ui.h"
#include "lang.h"
#include "state.h"
#include "exec.h"
#include "plugin.h"
#if !defined(NSIS_CONFIG_VISIBLE_SUPPORT) && !defined(NSIS_CONFIG_SILENT_SUPPORT)
#error One of NSIS_CONFIG_SILENT_SUPPORT or NSIS_CONFIG_VISIBLE_SUPPORT must be defined.
#endif
#ifdef NSIS_COMPRESS_WHOLE
extern HANDLE dbd_hFile;
#endif
TCHAR g_caption[NSIS_MAX_STRLEN*2];
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
HWND g_hwnd;
HANDLE g_hInstance;
#endif
void NSISCALL CleanUp();
TCHAR *ValidateTempDir()
{
validate_filename(state_temp_dir);
if (!validpathspec(state_temp_dir))
return NULL;
addtrailingslash(state_temp_dir);
CreateDirectory(state_temp_dir, NULL);
// state_language is used as a temp var here
return my_GetTempFileName(state_language, state_temp_dir);
}
void *g_SHGetFolderPath;
NSIS_ENTRYPOINT_GUINOCRT
EXTERN_C void NSISWinMainNOCRT()
{
int ret = 0;
const TCHAR *m_Err = _LANG_ERRORWRITINGTEMP;
int cl_flags = 0;
TCHAR *realcmds;
TCHAR seekchar=_T(' ');
TCHAR *cmdline;
InitCommonControls();
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
#if defined(NSIS_SUPPORT_ACTIVEXREG) || defined(NSIS_SUPPORT_CREATESHORTCUT)
{
extern HRESULT g_hres;
g_hres=OleInitialize(NULL);
}
#endif
// load shfolder.dll before any script code is executed to avoid
// weird situations where SetOutPath or even the extraction of
// shfolder.dll will cause unexpected behavior.
//
// this also prevents the following:
//
// SetOutPath "C:\Program Files\NSIS" # maybe read from reg
// File shfolder.dll
// Delete $PROGRAMFILES\shfolder.dll # can't be deleted, as the
// # new shfolder.dll is used
// # to find its own path.
g_SHGetFolderPath = myGetProcAddress(MGA_SHGetFolderPath);
{
// workaround for bug #1008632
// http://sourceforge.net/tracker/index.php?func=detail&aid=1008632&group_id=22049&atid=373085
//
// without this, SHGetSpecialFolderLocation doesn't always recognize
// some special folders, like the desktop folder for all users, on
// Windows 9x. unlike SHGetSpecialFolderPath, which is not available
// on all versions of Windows, SHGetSpecialFolderLocation doesn't try
// too hard to make sure the caller gets what he asked for. so we give
// it a little push in the right direction by doing part of the work
// for it.
//
// part of what SHGetFileInfo does, is to convert a path into an idl.
// to do this conversion, it first needs to initialize the list of
// special idls, which are exactly the idls we use to get the paths
// of special folders (CSIDL_*).
SHFILEINFO shfi;
SHGetFileInfo(_T(""), 0, &shfi, sizeof(SHFILEINFO), 0);
}
mystrcpy(g_caption,_LANG_GENERIC_ERROR);
mystrcpy(state_command_line, GetCommandLine());
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
g_hInstance = GetModuleHandle(NULL);
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
cmdline = state_command_line;
if (*cmdline == _T('\"')) seekchar = *cmdline++;
cmdline=findchar(cmdline, seekchar);
cmdline=CharNext(cmdline);
realcmds=cmdline;
while (*cmdline)
{
// skip over any spaces
while (*cmdline == _T(' ')) cmdline++;
// get char we should look for to get the next parm
seekchar = _T(' ');
if (cmdline[0] == _T('\"'))
{
cmdline++;
seekchar = _T('\"');
}
// is it a switch?
if (cmdline[0] == _T('/'))
{
cmdline++;
#define END_OF_ARG(c) (c == _T(' ') || c == _T('\0'))
#if defined(NSIS_CONFIG_VISIBLE_SUPPORT) && defined(NSIS_CONFIG_SILENT_SUPPORT)
if (cmdline[0] == _T('S') && END_OF_ARG(cmdline[1]))
cl_flags |= FH_FLAGS_SILENT;
#endif//NSIS_CONFIG_SILENT_SUPPORT && NSIS_CONFIG_VISIBLE_SUPPORT
#ifdef NSIS_CONFIG_CRC_SUPPORT
if (CMP4CHAR(cmdline, _T("NCRC")) && END_OF_ARG(cmdline[4]))
cl_flags |= FH_FLAGS_NO_CRC;
#endif//NSIS_CONFIG_CRC_SUPPORT
if (CMP4CHAR(cmdline-2, _T(" /D=")))
{
*(cmdline-2)=_T('\0'); // keep this from being passed to uninstaller if necessary
mystrcpy(state_install_directory,cmdline+2);
break; // /D= must always be last
}
}
// skip over our parm
cmdline = findchar(cmdline, seekchar);
// skip the quote
if (*cmdline == _T('\"'))
cmdline++;
}
GetTempPath(NSIS_MAX_STRLEN, state_temp_dir);
if (!ValidateTempDir())
{
GetWindowsDirectory(state_temp_dir, NSIS_MAX_STRLEN - 5); // leave space for \Temp
mystrcat(state_temp_dir, _T("\\Temp"));
if (!ValidateTempDir())
{
// There does not seem to be a API to get the low temp dir directly, so we build the path on our own
GetTempPath(NSIS_MAX_STRLEN - 4, state_temp_dir); // leave space for \Low
mystrcat(state_temp_dir, _T("Low"));
// If we don't call SetEnvironmentVariable
// child processes will use %temp% and not %temp%\Low
// and some apps probably can't handle a read only %temp%
// Do it before ValidateTempDir() because it appends a backslash.
// TODO: Should this be moved to ValidateTempDir() so it also updates for %windir%\Temp?
SetEnvironmentVariable(_T("TEMP"), state_temp_dir);
SetEnvironmentVariable(_T("TMP"), state_temp_dir);
if (!ValidateTempDir())
{
goto end;
}
}
}
DeleteFile(state_language);
m_Err = loadHeaders(cl_flags);
if (m_Err) goto end;
#ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
if (g_is_uninstaller)
{
TCHAR *p = findchar(state_command_line, 0);
// state_command_line has state_install_directory right after it in memory, so reading
// a bit over state_command_line won't do any harm
while (p >= state_command_line && !CMP4CHAR(p, _T(" _?="))) p--;
m_Err = _LANG_UNINSTINITERROR;
if (p >= state_command_line)
{
*p=0; // terminate before "_?="
p+=4; // skip over " _?="
if (is_valid_instpath(p))
{
mystrcpy(state_install_directory, p);
mystrcpy(state_output_directory, p);
m_Err = 0;
}
else
{
goto end;
}
}
else
{
int x;
mystrcat(state_temp_dir,_T("~nsu.tmp"));
// check if already running from uninstaller temp dir
// this prevents recursive uninstaller calls
if (!lstrcmpi(state_temp_dir,state_exe_directory))
goto end;
CreateDirectory(state_temp_dir,NULL);
SetCurrentDirectory(state_temp_dir);
if (!state_install_directory[0])
mystrcpy(state_install_directory,state_exe_directory);
mystrcpy(g_usrvars[0], realcmds);
SET2CHAR(g_usrvars[1], _T("A\0"));
for (x = 0; x < 26; x ++)
{
static TCHAR buf2[NSIS_MAX_STRLEN];
GetNSISString(buf2,g_header->str_uninstchild); // $TEMP\$1u_.exe
DeleteFile(buf2); // clean up after all the other ones if they are there
if (m_Err) // not done yet
{
// copy file
if (CopyFile(state_exe_path,buf2,TRUE))
{
HANDLE hProc;
#ifdef NSIS_SUPPORT_MOVEONREBOOT
MoveFileOnReboot(buf2,NULL);
#endif
GetNSISString(buf2,g_header->str_uninstcmd); // '"$TEMP\$1u_.exe" $0 _?=$INSTDIR\'
hProc=myCreateProcess(buf2);
if (hProc)
{
CloseHandle(hProc);
// success
m_Err = 0;
}
}
}
g_usrvars[1][0]++;
}
#ifdef NSIS_SUPPORT_MOVEONREBOOT
MoveFileOnReboot(state_temp_dir,NULL);
#endif
goto end;
}
}
#endif//NSIS_CONFIG_UNINSTALL_SUPPORT
g_exec_flags.errlvl = -1;
ret = ui_doinstall();
#ifdef NSIS_CONFIG_LOG
#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT)
log_write(1);
#endif//!NSIS_CONFIG_LOG_ODS && !NSIS_CONFIG_LOG_STDOUT
#endif//NSIS_CONFIG_LOG
end:
CleanUp();
#if defined(NSIS_SUPPORT_ACTIVEXREG) || defined(NSIS_SUPPORT_CREATESHORTCUT)
OleUninitialize();
#endif
if (m_Err)
{
my_MessageBox(m_Err, MB_OK | MB_ICONSTOP | (IDOK << 21));
ExitProcess(2);
}
#ifdef NSIS_SUPPORT_REBOOT
if (g_exec_flags.reboot_called)
{
BOOL (WINAPI *OPT)(HANDLE, DWORD,PHANDLE);
BOOL (WINAPI *LPV)(LPCTSTR,LPCTSTR,PLUID);
BOOL (WINAPI *ATP)(HANDLE,BOOL,PTOKEN_PRIVILEGES,DWORD,PTOKEN_PRIVILEGES,PDWORD);
OPT=myGetProcAddress(MGA_OpenProcessToken);
LPV=myGetProcAddress(MGA_LookupPrivilegeValue);
ATP=myGetProcAddress(MGA_AdjustTokenPrivileges);
if (OPT && LPV && ATP)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
if (OPT(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
LPV(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
ATP(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
}
}
if (!ExitWindowsEx(EWX_REBOOT,0))
ExecuteCallbackFunction(CB_ONREBOOTFAILED);
}
#endif//NSIS_SUPPORT_REBOOT
if (g_exec_flags.errlvl != -1)
ret = g_exec_flags.errlvl;
ExitProcess(ret);
}
void NSISCALL CleanUp()
{
if (g_db_hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(g_db_hFile);
g_db_hFile = INVALID_HANDLE_VALUE;
}
#ifdef NSIS_COMPRESS_WHOLE
if (dbd_hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(dbd_hFile);
dbd_hFile = INVALID_HANDLE_VALUE;
}
#endif
// Notify plugins that we are about to unload
Plugins_UnloadAll();
#ifdef NSIS_CONFIG_PLUGIN_SUPPORT
// Clean up after plug-ins
myDelete(state_plugins_dir, DEL_DIR | DEL_RECURSE | DEL_REBOOT);
#endif // NSIS_CONFIG_PLUGIN_SUPPORT
}