
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
388 lines
9.9 KiB
C
388 lines
9.9 KiB
C
// Unicode support by Jim Park & Olivier Marcoux
|
|
|
|
#include "../../../Source/Platform.h"
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
|
|
#ifndef _CRT_STRINGIZE
|
|
#define __CRT_STRINGIZE(_Value) #_Value
|
|
#define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value)
|
|
#endif /* _CRT_STRINGIZE */
|
|
|
|
#define STR_SIZE 1024
|
|
|
|
void RegFile(TCHAR cmd, TCHAR *file, int x64);
|
|
void RegDll(TCHAR *file);
|
|
void RegTypeLib(TCHAR *file);
|
|
void DeleteFileOnReboot(TCHAR *pszFile);
|
|
|
|
NSIS_ENTRYPOINT_GUINOCRT
|
|
EXTERN_C void NSISWinMainNOCRT()
|
|
{
|
|
TCHAR *cmdline;
|
|
TCHAR seekchar = _T(' ');
|
|
|
|
cmdline = GetCommandLine();
|
|
if (*cmdline == _T('\"'))
|
|
seekchar = *cmdline++;
|
|
|
|
while (*cmdline && *cmdline != seekchar)
|
|
cmdline = CharNext(cmdline);
|
|
cmdline = CharNext(cmdline);
|
|
while (*cmdline == _T(' '))
|
|
cmdline++;
|
|
|
|
if (*cmdline++ != _T('/'))
|
|
{
|
|
ExitProcess(1);
|
|
}
|
|
|
|
if (*cmdline == _T('S'))
|
|
{
|
|
HKEY rootkey;
|
|
TCHAR *keyname, *file; // These are turned into heap memory to avoid _chkstk
|
|
keyname = (TCHAR*) GlobalAlloc(GPTR, STR_SIZE*sizeof(TCHAR));
|
|
file = (TCHAR*) GlobalAlloc(GPTR, STR_SIZE*sizeof(TCHAR));
|
|
|
|
if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NSIS.Library.RegTool.v3"), 0, KEY_READ, &rootkey)))
|
|
{
|
|
while (RegEnumKey(rootkey, 0, keyname, STR_SIZE) == ERROR_SUCCESS)
|
|
{
|
|
HKEY key;
|
|
|
|
if (SUCCEEDED(RegOpenKeyEx(rootkey, keyname, 0, KEY_READ, &key)))
|
|
{
|
|
DWORD t, count, l = sizeof(DWORD);
|
|
|
|
if (SUCCEEDED(RegQueryValueEx(key, _T("count"), NULL, &t, (LPBYTE) &count, &l)) && t == REG_DWORD)
|
|
{
|
|
DWORD j;
|
|
TCHAR valname[128], mode[3];
|
|
|
|
for (j = 1; j <= count; j++)
|
|
{
|
|
wsprintf(valname, _T("%u.mode"), j);
|
|
l = sizeof(mode);
|
|
if (FAILED(RegQueryValueEx(key, valname, NULL, &t, (LPBYTE) mode, &l)) || t != REG_SZ)
|
|
continue;
|
|
|
|
wsprintf(valname, _T("%u.file"), j);
|
|
l = STR_SIZE*sizeof(TCHAR);
|
|
if (FAILED(RegQueryValueEx(key, valname, NULL, &t, (LPBYTE) file, &l)) || t != REG_SZ)
|
|
continue;
|
|
|
|
// JP: Note, if this mode[1] is used as anything but a boolean later on,
|
|
// we'll need to consider the next line carefully.
|
|
RegFile(mode[0], file, mode[1] == 'X');
|
|
}
|
|
}
|
|
|
|
RegCloseKey(key);
|
|
RegDeleteKey(rootkey, keyname);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(rootkey);
|
|
RegDeleteKey(HKEY_LOCAL_MACHINE, _T("Software\\NSIS.Library.RegTool.v3"));
|
|
}
|
|
|
|
{
|
|
if (GetModuleFileName(GetModuleHandle(NULL), file, STR_SIZE))
|
|
{
|
|
DeleteFileOnReboot(file);
|
|
}
|
|
}
|
|
GlobalFree(keyname);
|
|
GlobalFree(file);
|
|
}
|
|
else
|
|
{
|
|
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
|
|
OleInitialize(NULL);
|
|
|
|
if (*cmdline == _T('D'))
|
|
{
|
|
RegDll(cmdline + 1);
|
|
}
|
|
else if (*cmdline == _T('T'))
|
|
{
|
|
RegTypeLib(cmdline + 1);
|
|
}
|
|
|
|
OleUninitialize();
|
|
SetErrorMode(0);
|
|
}
|
|
|
|
ExitProcess(0);
|
|
}
|
|
|
|
void SafeWow64EnableWow64FsRedirection(BOOL Wow64FsEnableRedirection)
|
|
{
|
|
HMODULE kernel = GetModuleHandle(_T("kernel32"));
|
|
if (kernel)
|
|
{
|
|
FARPROC proc = GetProcAddress(kernel, "Wow64EnableWow64FsRedirection");
|
|
if (proc)
|
|
{
|
|
typedef BOOL (WINAPI *Wow64EnableWow64FsRedirectionPtr)(BOOL);
|
|
Wow64EnableWow64FsRedirectionPtr Wow64EnableWow64FsRedirectionFunc =
|
|
(Wow64EnableWow64FsRedirectionPtr) proc;
|
|
|
|
Wow64EnableWow64FsRedirectionFunc(Wow64FsEnableRedirection);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RegFile(TCHAR cmd, TCHAR *file, int x64)
|
|
{
|
|
TCHAR* self; // These are turned into heap memory to avoid _chkstk
|
|
TCHAR* cmdline;
|
|
|
|
int ready = 0;
|
|
|
|
if (!*file || (cmd != _T('D') && cmd != _T('T') && cmd != _T('E')))
|
|
return;
|
|
|
|
self = (TCHAR*) GlobalAlloc(GPTR, sizeof(TCHAR)*STR_SIZE);
|
|
cmdline = (TCHAR*) GlobalAlloc(GPTR, sizeof(TCHAR)*STR_SIZE);
|
|
|
|
if (cmd == _T('E'))
|
|
{
|
|
wsprintf(cmdline, _T("\"%s\" /regserver"), file);
|
|
ready++;
|
|
}
|
|
else if (!x64)
|
|
{
|
|
if (GetModuleFileName(GetModuleHandle(NULL), self, STR_SIZE))
|
|
{
|
|
wsprintf(cmdline, _T("\"%s\" /%c%s"), self, cmd, file);
|
|
ready++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetSystemDirectory(self, STR_SIZE))
|
|
{
|
|
wsprintf(cmdline, _T("\"%s\\regsvr32.exe\" /s \"%s\""), self, file);
|
|
ready++;
|
|
|
|
SafeWow64EnableWow64FsRedirection(FALSE);
|
|
}
|
|
}
|
|
|
|
if (ready)
|
|
{
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO si = { sizeof(STARTUPINFO) };
|
|
|
|
if (CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
|
|
{
|
|
CloseHandle(pi.hThread);
|
|
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
|
|
CloseHandle(pi.hProcess);
|
|
}
|
|
|
|
if (x64)
|
|
{
|
|
SafeWow64EnableWow64FsRedirection(TRUE);
|
|
}
|
|
}
|
|
|
|
GlobalFree(self);
|
|
GlobalFree(cmdline);
|
|
}
|
|
|
|
void RegDll(TCHAR *file)
|
|
{
|
|
HMODULE mod = LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
|
if (mod)
|
|
{
|
|
FARPROC regfunc = GetProcAddress(mod, "DllRegisterServer");
|
|
if (regfunc)
|
|
regfunc();
|
|
FreeLibrary(mod);
|
|
}
|
|
}
|
|
|
|
void RegTypeLib(TCHAR *file)
|
|
{
|
|
#ifdef _UNICODE
|
|
WCHAR* wfile = file;
|
|
#else
|
|
WCHAR wfile[STR_SIZE];
|
|
if (MultiByteToWideChar(CP_ACP, 0, file, -1, wfile, STR_SIZE) == 0)
|
|
return;
|
|
#endif
|
|
{
|
|
ITypeLib* tlib;
|
|
if (SUCCEEDED(LoadTypeLib(wfile, &tlib))) {
|
|
RegisterTypeLib(tlib, wfile, NULL);
|
|
tlib->lpVtbl->Release(tlib);
|
|
}
|
|
}
|
|
}
|
|
|
|
char *mystrstriA(char *a, const char *b)
|
|
{
|
|
int l = lstrlenA(b);
|
|
while (lstrlenA(a) >= l)
|
|
{
|
|
char c = a[l];
|
|
a[l] = 0;
|
|
if (!lstrcmpiA(a, b))
|
|
{
|
|
a[l] = c;
|
|
return a;
|
|
}
|
|
a[l] = c;
|
|
a = CharNextA(a);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void mini_memcpy(void *out, const void *in, int len)
|
|
{
|
|
char *c_out=(char*)out;
|
|
char *c_in=(char *)in;
|
|
while (len-- > 0)
|
|
{
|
|
*c_out++=*c_in++;
|
|
}
|
|
}
|
|
|
|
HANDLE myOpenFile(const TCHAR *fn, DWORD da, DWORD cd)
|
|
{
|
|
int attr = GetFileAttributes(fn);
|
|
return CreateFile(
|
|
fn,
|
|
da,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
cd,
|
|
attr == INVALID_FILE_ATTRIBUTES ? 0 : attr,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
/** Modifies the wininit.ini file to rename / delete a file.
|
|
*
|
|
* @param prevName The previous / current name of the file.
|
|
* @param newName The new name to move the file to. If NULL, the current file
|
|
* will be deleted.
|
|
*/
|
|
void RenameViaWininit(const TCHAR* prevName, const TCHAR* newName)
|
|
{
|
|
static char szRenameLine[1024];
|
|
static TCHAR wininit[1024];
|
|
static TCHAR tmpbuf[1024];
|
|
|
|
int cchRenameLine;
|
|
LPCSTR szRenameSec = "[Rename]\r\n"; // rename section marker
|
|
HANDLE hfile;
|
|
DWORD dwFileSize;
|
|
DWORD dwBytes;
|
|
DWORD dwRenameLinePos;
|
|
char *pszWinInit; // Contains the file contents of wininit.ini
|
|
|
|
int spn; // length of the short path name in TCHARs.
|
|
|
|
lstrcpy(tmpbuf, _T("NUL"));
|
|
|
|
if (newName) {
|
|
// create the file if it's not already there to prevent GetShortPathName from failing
|
|
CloseHandle(myOpenFile(newName,0,CREATE_NEW));
|
|
spn = GetShortPathName(newName,tmpbuf,1024);
|
|
if (!spn || spn > 1024)
|
|
return;
|
|
}
|
|
// wininit is used as a temporary here
|
|
spn = GetShortPathName(prevName,wininit,1024);
|
|
if (!spn || spn > 1024)
|
|
return;
|
|
#ifdef _UNICODE
|
|
cchRenameLine = wsprintfA(szRenameLine, "%ls=l%s\r\n", tmpbuf, wininit);
|
|
#else
|
|
cchRenameLine = wsprintfA(szRenameLine, "%s=%s\r\n", tmpbuf, wininit);
|
|
#endif
|
|
// Get the path to the wininit.ini file.
|
|
GetWindowsDirectory(wininit, 1024-16);
|
|
lstrcat(wininit, _T("\\wininit.ini"));
|
|
|
|
hfile = myOpenFile(wininit, GENERIC_READ | GENERIC_WRITE, OPEN_ALWAYS);
|
|
|
|
if (hfile != INVALID_HANDLE_VALUE)
|
|
{
|
|
// We are now working on the Windows wininit file
|
|
dwFileSize = GetFileSize(hfile, NULL);
|
|
pszWinInit = (char*) GlobalAlloc(GPTR, dwFileSize + cchRenameLine + 10);
|
|
|
|
if (pszWinInit != NULL)
|
|
{
|
|
if (ReadFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL) && dwFileSize == dwBytes)
|
|
{
|
|
// Look for the rename section in the current file.
|
|
LPSTR pszRenameSecInFile = mystrstriA(pszWinInit, szRenameSec);
|
|
if (pszRenameSecInFile == NULL)
|
|
{
|
|
// No rename section. So we add it to the end of file.
|
|
lstrcpyA(pszWinInit+dwFileSize, szRenameSec);
|
|
dwFileSize += 10;
|
|
dwRenameLinePos = dwFileSize;
|
|
}
|
|
else
|
|
{
|
|
// There is a rename section, but is there another section after it?
|
|
char *pszFirstRenameLine = pszRenameSecInFile+10;
|
|
char *pszNextSec = mystrstriA(pszFirstRenameLine,"\n[");
|
|
if (pszNextSec)
|
|
{
|
|
char *p = pszWinInit + dwFileSize;
|
|
char *pEnd = pszWinInit + dwFileSize + cchRenameLine;
|
|
|
|
while (p > pszNextSec)
|
|
{
|
|
*pEnd-- = *p--;
|
|
}
|
|
|
|
dwRenameLinePos = pszNextSec - pszWinInit + 1; // +1 for the \n
|
|
}
|
|
// rename section is last, stick item at end of file
|
|
else dwRenameLinePos = dwFileSize;
|
|
}
|
|
|
|
mini_memcpy(&pszWinInit[dwRenameLinePos], szRenameLine, cchRenameLine);
|
|
dwFileSize += cchRenameLine;
|
|
|
|
SetFilePointer(hfile, 0, NULL, FILE_BEGIN);
|
|
WriteFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL);
|
|
|
|
GlobalFree(pszWinInit);
|
|
}
|
|
}
|
|
|
|
CloseHandle(hfile);
|
|
}
|
|
}
|
|
|
|
void DeleteFileOnReboot(TCHAR *pszFile)
|
|
{
|
|
BOOL fOk = 0;
|
|
HMODULE hLib=GetModuleHandle(_T("KERNEL32.dll"));
|
|
if (hLib)
|
|
{
|
|
typedef BOOL (WINAPI *mfea_t)(LPCTSTR lpExistingFileName,LPCTSTR lpNewFileName,DWORD dwFlags);
|
|
mfea_t mfea;
|
|
mfea=(mfea_t) GetProcAddress(hLib,_CRT_STRINGIZE(MoveFileEx));
|
|
if (mfea)
|
|
{
|
|
fOk=mfea(pszFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
|
|
}
|
|
}
|
|
|
|
if (!fOk)
|
|
{
|
|
RenameViaWininit(pszFile, NULL);
|
|
}
|
|
}
|