NSIS/Source/exehead/Main.c
kichik 0aed504f4a happy new year!
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@5917 212acab6-be3b-0410-9dea-997c60f758d6
2009-02-01 14:44:30 +00:00

351 lines
9.4 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.
*/
#include "../Platform.h"
#include <shlobj.h>
#include <shellapi.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
char g_caption[NSIS_MAX_STRLEN*2];
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
HWND g_hwnd;
HANDLE g_hInstance;
#endif
void NSISCALL CleanUp();
char *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;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpszCmdParam, int nCmdShow)
{
int ret = 0;
const char *m_Err = _LANG_ERRORWRITINGTEMP;
int cl_flags = 0;
char *realcmds;
char seekchar=' ';
char *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_SHGetFolderPathA);
{
// 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("", 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 == '\"') seekchar = *cmdline++;
cmdline=findchar(cmdline, seekchar);
cmdline=CharNext(cmdline);
realcmds=cmdline;
while (*cmdline)
{
// skip over any spaces
while (*cmdline == ' ') cmdline++;
// get char we should look for to get the next parm
seekchar = ' ';
if (cmdline[0] == '\"')
{
cmdline++;
seekchar = '\"';
}
// is it a switch?
if (cmdline[0] == '/')
{
cmdline++;
// this only works with spaces because they have just one bit on
#define END_OF_ARG(c) (((c)|' ')==' ')
#if defined(NSIS_CONFIG_VISIBLE_SUPPORT) && defined(NSIS_CONFIG_SILENT_SUPPORT)
if (cmdline[0] == '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 (*(LPDWORD)cmdline == CHAR4_TO_DWORD('N','C','R','C') && END_OF_ARG(cmdline[4]))
cl_flags |= FH_FLAGS_NO_CRC;
#endif//NSIS_CONFIG_CRC_SUPPORT
if (*(LPDWORD)(cmdline-2) == CHAR4_TO_DWORD(' ', '/', 'D','='))
{
*(LPDWORD)(cmdline-2)=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 == '\"')
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, "\\Temp");
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)
{
char *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 && *(LPDWORD)p != CHAR4_TO_DWORD(' ', '_', '?', '=')) 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,"~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);
*(LPWORD)g_usrvars[1] = CHAR2_TO_WORD('A',0);
for (x = 0; x < 26; x ++)
{
static char 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);
return 0;
}
#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_LookupPrivilegeValueA);
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);
return 0;
}
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
}