TCHAR cannot be used in RegTool because it must be able to run on Win9x.
RegTool now implements A and W functions in the same binary. Bitness mixing is still problematic. git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6858 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
parent
c401748d95
commit
d80b364e1d
6 changed files with 445 additions and 383 deletions
|
@ -1,382 +0,0 @@
|
|||
// Unicode support by Jim Park & Olivier Marcoux
|
||||
|
||||
#include "../../../Source/Platform.h"
|
||||
#include <windows.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);
|
||||
BOOL 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
|
||||
);
|
||||
}
|
||||
|
||||
#ifndef _WIN64
|
||||
/** 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 = BUGBUG64TRUNCATE(DWORD, 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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL DeleteFileOnReboot(TCHAR *pszFile)
|
||||
{
|
||||
BOOL fOk =
|
||||
MoveFileEx(pszFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
|
||||
#ifndef _WIN64
|
||||
if (!fOk)
|
||||
{
|
||||
RenameViaWininit(pszFile, NULL);
|
||||
fOk = TRUE; // BUGBUG: We just pretend everything is OK, nobody checks our return value anyway
|
||||
}
|
||||
#endif
|
||||
return fOk;
|
||||
}
|
422
Contrib/Library/RegTool/RegTool.cpp
Normal file
422
Contrib/Library/RegTool/RegTool.cpp
Normal file
|
@ -0,0 +1,422 @@
|
|||
// RegTool v3
|
||||
// Unicode support by Jim Park & Olivier Marcoux
|
||||
|
||||
#include "../../../Source/Platform.h"
|
||||
#include <windows.h>
|
||||
|
||||
#define STR_SIZE 1024
|
||||
|
||||
|
||||
/*
|
||||
All A/W functions need this ugly hack so we can call them in template functions.
|
||||
Everything is implemented in template functions because the x86 version needs to
|
||||
call the W functions on NT and the A functions on 9x.
|
||||
The macros assume that "T" is a [W]CHAR type.
|
||||
*/
|
||||
#define MKSTR(str) ( sizeof(T) > 1 ? (const T*) L##str : (const T*) str )
|
||||
#ifdef UNICODE
|
||||
#define CALL(func) hack::func##W<T>
|
||||
#else
|
||||
#define CALL(func) hack::func##A<T>
|
||||
#endif
|
||||
#define CALL_wsprintf (sizeof(T) > 1 ? (int(*)(T*,const T*,...)) wsprintfW : (int(*)(T*,const T*,...)) wsprintfA)
|
||||
namespace hack {
|
||||
// Allow cast from [const] T* to [W]CHAR* but nothing else (losing constness is acceptable).
|
||||
inline WCHAR* WP(const WCHAR*p) { return (WCHAR*) p; }
|
||||
inline WCHAR* WP(const CHAR*p) { return (WCHAR*) p; }
|
||||
inline CHAR* NP(const WCHAR*p) { return (CHAR*) p; }
|
||||
inline CHAR* NP(const CHAR*p) { return (CHAR*) p; }
|
||||
// These function names rely on the C preprocessor & PSDK macros to append A/W to their name so they can be found by the CALL macro.
|
||||
template<class T> T* GetCommandLine() { return sizeof(T) > 1 ? (T*) ::GetCommandLineW() : (T*) ::GetCommandLineA(); }
|
||||
template<class T> T* CharNext(const T*p1) { return sizeof(T) > 1 ? (T*) ::CharNextW(WP(p1)) : (T*) ::CharNextA(NP(p1)); }
|
||||
template<class T> T* lstrcpy(T*p1,const T*p2) { return sizeof(T) > 1 ? (T*) ::lstrcpyW(WP(p1),WP(p2)) : (T*) ::lstrcpyA(NP(p1),NP(p2)); }
|
||||
template<class T> T* lstrcat(T*p1,const T*p2) { return sizeof(T) > 1 ? (T*) ::lstrcatW(WP(p1),WP(p2)) : (T*) ::lstrcatA(NP(p1),NP(p2)); }
|
||||
template<class T> LONG RegEnumKey(HKEY p1, DWORD p2, T*p3,DWORD p4) { return sizeof(T) > 1 ? ::RegEnumKeyW(p1,p2,WP(p3),p4) : ::RegEnumKeyA(p1,p2,NP(p3),p4); }
|
||||
template<class T> LONG RegOpenKeyEx(HKEY p1,const T*p2,DWORD p3,REGSAM p4,PHKEY p5) { return sizeof(T) > 1 ? ::RegOpenKeyExW(p1,WP(p2),p3,p4,p5) : ::RegOpenKeyExA(p1,NP(p2),p3,p4,p5); }
|
||||
template<class T> LONG RegQueryValueEx(HKEY p1,const T*p2,LPDWORD p3,LPDWORD p4,LPBYTE p5,LPDWORD p6) { return sizeof(T) > 1 ? ::RegQueryValueExW(p1,WP(p2),p3,p4,p5,p6) : ::RegQueryValueExA(p1,NP(p2),p3,p4,p5,p6); }
|
||||
template<class T> LONG RegDeleteKey(HKEY p1,const T*p2) { return sizeof(T) > 1 ? ::RegDeleteKeyW(p1,WP(p2)) : ::RegDeleteKeyA(p1,NP(p2)); }
|
||||
template<class T> DWORD GetModuleFileName(HMODULE p1,T*p2,DWORD p3) { return sizeof(T) > 1 ? ::GetModuleFileNameW(p1,WP(p2),p3) : ::GetModuleFileNameA(p1,NP(p2),p3); }
|
||||
template<class T> HMODULE LoadLibraryEx(const T*p1,void*p2,DWORD p3) { return sizeof(T) > 1 ? ::LoadLibraryExW(WP(p1),p2,p3) : ::LoadLibraryExA(NP(p1),p2,p3); }
|
||||
template<class T> UINT GetWindowsDirectory(const T*p1,UINT p2) { return sizeof(T) > 1 ? ::GetWindowsDirectoryW(WP(p1),p2) : ::GetWindowsDirectoryA(NP(p1),p2); }
|
||||
template<class T> UINT GetSystemDirectory(const T*p1,UINT p2) { return sizeof(T) > 1 ? ::GetSystemDirectoryW(WP(p1),p2) : ::GetSystemDirectoryA(NP(p1),p2); }
|
||||
template<class T> DWORD GetShortPathName(const T*p1,const T*p2,DWORD p3) { return sizeof(T) > 1 ? ::GetShortPathNameW(WP(p1),WP(p2),p3) : ::GetShortPathNameA(NP(p1),NP(p2),p3); }
|
||||
template<class T> DWORD GetFileAttributes(const T*p1) { return sizeof(T) > 1 ? ::GetFileAttributesW(WP(p1)) : ::GetFileAttributesA(NP(p1)); }
|
||||
template<class T> BOOL MoveFileEx(const T*p1,const T*p2,DWORD p3) { return sizeof(T) > 1 ? ::MoveFileExW(WP(p1),WP(p2),p3) : ::MoveFileExA(NP(p1),NP(p2),p3); }
|
||||
template<class T> HANDLE CreateFile(const T*p1,DWORD p2,DWORD p3,LPSECURITY_ATTRIBUTES p4,DWORD p5,DWORD p6,HANDLE p7) { return sizeof(T) > 1 ? ::CreateFileW(WP(p1),p2,p3,p4,p5,p6,p7) : ::CreateFileA(NP(p1),p2,p3,p4,p5,p6,p7); }
|
||||
template<class T> BOOL CreateProcess(const T*p1,const T*p2,LPSECURITY_ATTRIBUTES p3,LPSECURITY_ATTRIBUTES p4,BOOL p5,DWORD p6,LPVOID p7,const T*p8,STARTUPINFO*p9,LPPROCESS_INFORMATION p10) { return sizeof(T) > 1 ? ::CreateProcessW(WP(p1),WP(p2),p3,p4,p5,p6,p7,WP(p8),(STARTUPINFOW*)p9,p10) : ::CreateProcessA(NP(p1),NP(p2),p3,p4,p5,p6,p7,NP(p8),(STARTUPINFOA*)p9,p10); }
|
||||
}
|
||||
|
||||
|
||||
static bool IsWinNT()
|
||||
{
|
||||
#ifdef _WIN64
|
||||
return true;
|
||||
#else
|
||||
LPCWSTR str = L"count"; // Using this string because it's already used in other parts of the code
|
||||
return CharNextW(str) != NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SafeWow64EnableWow64FsRedirection(BYTE EnableFsRedirection)
|
||||
{
|
||||
#ifndef _WIN64
|
||||
HMODULE hK32 = LoadLibraryA("KERNEL32");
|
||||
FARPROC proc = GetProcAddress(hK32, "Wow64EnableWow64FsRedirection");
|
||||
if (proc)
|
||||
{
|
||||
typedef BYTE WINNTBOOLEAN;
|
||||
typedef WINNTBOOLEAN (WINAPI*W64EW64FSR)(WINNTBOOLEAN);
|
||||
W64EW64FSR Wow64EnableWow64FsRedirectionFunc = (W64EW64FSR) proc;
|
||||
Wow64EnableWow64FsRedirectionFunc(EnableFsRedirection);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> static HANDLE myOpenFile(const T *fn, DWORD da, DWORD cd)
|
||||
{
|
||||
DWORD attr = CALL(GetFileAttributes)(fn), share = FILE_SHARE_READ;
|
||||
return CALL(CreateFile)(fn, da, share, NULL, cd, attr == INVALID_FILE_ATTRIBUTES ? 0 : attr, NULL);
|
||||
}
|
||||
|
||||
#ifndef _WIN64
|
||||
/** 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.
|
||||
*/
|
||||
template<class T> void RenameViaWininit(const T* prevName, const T* newName) // Note: Not thread safe!
|
||||
{
|
||||
static char szRenameLine[1024];
|
||||
static T wininit[1024];
|
||||
static T tmpbuf[1024];
|
||||
|
||||
int cchRenameLine;
|
||||
LPCSTR szRenameSec = "[Rename]\r\n"; // rename section marker
|
||||
HANDLE hfile;
|
||||
DWORD dwFileSize;
|
||||
DWORD dwBytes, dwRenameLinePos;
|
||||
char *pszWinInit; // Contains the file contents of wininit.ini
|
||||
|
||||
int spn; // length of the short path name in TCHARs.
|
||||
|
||||
CALL(lstrcpy)(tmpbuf, MKSTR("NUL"));
|
||||
|
||||
if (newName) {
|
||||
// create the file if it's not already there to prevent GetShortPathName from failing
|
||||
CloseHandle(myOpenFile(newName,0,CREATE_NEW));
|
||||
spn = CALL(GetShortPathName)(newName,tmpbuf,COUNTOF(tmpbuf));
|
||||
if (!spn || spn > 1024)
|
||||
return;
|
||||
}
|
||||
// wininit is used as a temporary here
|
||||
spn = CALL(GetShortPathName)(prevName,wininit,COUNTOF(wininit));
|
||||
if (!spn || spn > 1024)
|
||||
return;
|
||||
#ifdef _UNICODE
|
||||
cchRenameLine = wsprintfA(szRenameLine, "%S=%S\r\n", tmpbuf, wininit);
|
||||
#else
|
||||
cchRenameLine = wsprintfA(szRenameLine, "%s=%s\r\n", tmpbuf, wininit);
|
||||
#endif
|
||||
// Get the path to the wininit.ini file.
|
||||
CALL(GetWindowsDirectory)(wininit, COUNTOF(wininit)-16);
|
||||
CALL(lstrcat)(wininit, MKSTR("\\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 = BUGBUG64TRUNCATE(DWORD, 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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class T> BOOL DeleteFileOnReboot(const T *pszFile)
|
||||
{
|
||||
BOOL fOk = CALL(MoveFileEx)(pszFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
|
||||
#ifndef _WIN64
|
||||
if (!fOk && sizeof(T) == 1)
|
||||
{
|
||||
RenameViaWininit(pszFile, (const T*)NULL);
|
||||
fOk = TRUE; // BUGBUG: We just pretend everything is OK, nobody checks our return value anyway
|
||||
}
|
||||
#endif
|
||||
return fOk;
|
||||
}
|
||||
|
||||
template<class T> void RegFile(T cmd, const T *file, BOOL x64)
|
||||
{
|
||||
T *self; // These are allocated on the heap to avoid _chkstk
|
||||
T *cmdline;
|
||||
int ready = 0;
|
||||
|
||||
if (!*file || (cmd != _T('D') && cmd != _T('T') && cmd != _T('E')))
|
||||
return;
|
||||
|
||||
self = (T*) GlobalAlloc(GPTR, sizeof(T)*STR_SIZE);
|
||||
cmdline = (T*) GlobalAlloc(GPTR, sizeof(T)*STR_SIZE);
|
||||
|
||||
if (cmd == ('E'))
|
||||
{
|
||||
CALL_wsprintf(cmdline, MKSTR("\"%s\" /regserver"), file);
|
||||
ready++;
|
||||
}
|
||||
else if (!x64)
|
||||
{
|
||||
if (CALL(GetModuleFileName)(GetModuleHandle(NULL), self, STR_SIZE))
|
||||
{
|
||||
CALL_wsprintf(cmdline, MKSTR("\"%s\" /%c%s"), self, cmd, file);
|
||||
ready++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CALL(GetSystemDirectory)(self, STR_SIZE))
|
||||
{
|
||||
CALL_wsprintf(cmdline, MKSTR("\"%s\\regsvr32.exe\" /s \"%s\""), self, file);
|
||||
ready++;
|
||||
|
||||
SafeWow64EnableWow64FsRedirection(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (ready)
|
||||
{
|
||||
PROCESS_INFORMATION pi;
|
||||
BYTE sibuf[sizeof(T) > 1 ? sizeof(STARTUPINFOW) : sizeof(STARTUPINFOA)] = {0,};
|
||||
STARTUPINFO &si = (STARTUPINFO&) sibuf;
|
||||
si.cb = sizeof(sibuf);
|
||||
|
||||
if (CALL(CreateProcess)(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
|
||||
{
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
if (x64)
|
||||
{
|
||||
SafeWow64EnableWow64FsRedirection(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
GlobalFree(self);
|
||||
GlobalFree(cmdline);
|
||||
}
|
||||
|
||||
template<class T> void RegDll(const T *file)
|
||||
{
|
||||
HMODULE mod = CALL(LoadLibraryEx)(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
if (mod)
|
||||
{
|
||||
FARPROC regfunc = GetProcAddress(mod, "DllRegisterServer");
|
||||
if (regfunc)
|
||||
regfunc();
|
||||
FreeLibrary(mod);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> void RegTypeLib(T *file)
|
||||
{
|
||||
WCHAR wbuf[sizeof(T) > 1 ? 1 : STR_SIZE]; // Buffer only used by ANSI implementation!
|
||||
WCHAR *wfile = wbuf; // Not const because of RegisterTypeLib in old PSDK
|
||||
if (sizeof(T) > 1)
|
||||
wfile = (WCHAR*) file;
|
||||
else
|
||||
{
|
||||
if (MultiByteToWideChar(CP_ACP, 0, (const CHAR*) file, -1, wbuf, STR_SIZE) == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
ITypeLib* tlib;
|
||||
if (SUCCEEDED(LoadTypeLib(wfile, &tlib)))
|
||||
{
|
||||
RegisterTypeLib(tlib, wfile, NULL);
|
||||
tlib->Release();
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> int RegTool()
|
||||
{
|
||||
T *cmdline;
|
||||
T seekchar = (' ');
|
||||
|
||||
cmdline = CALL(GetCommandLine)();
|
||||
if (*cmdline == ('\"'))
|
||||
seekchar = *cmdline++;
|
||||
|
||||
while (*cmdline && *cmdline != seekchar)
|
||||
cmdline = CALL(CharNext)(cmdline);
|
||||
cmdline = CALL(CharNext)(cmdline);
|
||||
while (*cmdline == (' '))
|
||||
cmdline++;
|
||||
|
||||
if (*cmdline++ != ('/'))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (*cmdline == ('S'))
|
||||
{
|
||||
HKEY rootkey;
|
||||
T *keyname, *file; // These are allocated on the heap to avoid _chkstk
|
||||
keyname = (T*) GlobalAlloc(GPTR, STR_SIZE*sizeof(T));
|
||||
file = (T*) GlobalAlloc(GPTR, STR_SIZE*sizeof(T));
|
||||
|
||||
if (SUCCEEDED(RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\NSIS.Library.RegTool.v3", 0, KEY_READ, &rootkey)))
|
||||
{
|
||||
DWORD keyidx = 0;
|
||||
while (CALL(RegEnumKey)(rootkey, keyidx, keyname, STR_SIZE) == ERROR_SUCCESS)
|
||||
{
|
||||
HKEY key;
|
||||
|
||||
if (SUCCEEDED(CALL(RegOpenKeyEx)(rootkey, keyname, 0, KEY_READ, &key)))
|
||||
{
|
||||
DWORD t, count, l = sizeof(DWORD);
|
||||
|
||||
if (SUCCEEDED(CALL(RegQueryValueEx)(key, MKSTR("count"), NULL, &t, (LPBYTE) &count, &l)) && t == REG_DWORD)
|
||||
{
|
||||
DWORD j;
|
||||
T valname[128], mode[3];
|
||||
|
||||
for (j = 0; ++j <= count;)
|
||||
{
|
||||
CALL_wsprintf(valname, MKSTR("%u.mode"), j);
|
||||
l = sizeof(mode);
|
||||
if (FAILED(CALL(RegQueryValueEx)(key, valname, NULL, &t, (LPBYTE) mode, &l)) || t != REG_SZ)
|
||||
continue;
|
||||
|
||||
CALL_wsprintf(valname, MKSTR("%u.file"), j);
|
||||
l = STR_SIZE*sizeof(T);
|
||||
if (FAILED(CALL(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);
|
||||
|
||||
CALL(RegDeleteKey)(rootkey, keyname);
|
||||
}
|
||||
keyidx++; // Must increment this so we don't loop forever if a non-admin accidentally executes RegTool /S
|
||||
}
|
||||
|
||||
RegCloseKey(rootkey);
|
||||
RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\NSIS.Library.RegTool.v3");
|
||||
}
|
||||
|
||||
{
|
||||
if (CALL(GetModuleFileName)(GetModuleHandle(NULL), file, STR_SIZE))
|
||||
{
|
||||
DeleteFileOnReboot(file);
|
||||
}
|
||||
}
|
||||
GlobalFree(keyname);
|
||||
GlobalFree(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD orgerrmode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
|
||||
OleInitialize(NULL);
|
||||
|
||||
if (*cmdline == ('D'))
|
||||
{
|
||||
RegDll(cmdline + 1);
|
||||
}
|
||||
else if (*cmdline == ('T'))
|
||||
{
|
||||
RegTypeLib(cmdline + 1);
|
||||
}
|
||||
|
||||
OleUninitialize();
|
||||
SetErrorMode(orgerrmode);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NSIS_ENTRYPOINT_GUINOCRT
|
||||
EXTERN_C void NSISWinMainNOCRT()
|
||||
{
|
||||
int ec = IsWinNT() ? RegTool<WCHAR>() : RegTool<CHAR>();
|
||||
ExitProcess(ec);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
target = 'RegTool'
|
||||
|
||||
files = Split("""
|
||||
RegTool.c
|
||||
RegTool.cpp
|
||||
""")
|
||||
|
||||
libs = Split("""
|
||||
|
|
|
@ -8,6 +8,8 @@ Released on ? ?th, 2017
|
|||
|
||||
\S2{} Major Changes
|
||||
|
||||
\b Fixed RegTool Win9x bug
|
||||
|
||||
\b Added \R{execshellwait}{ExecShellWait}
|
||||
|
||||
\b Added \R{writeregmultistr}{WriteRegMultiStr} (\W{http://sf.net/p/nsis/feature-requests/382}{RFE #382}, \W{http://sf.net/p/nsis/patches/219}{patch #219})
|
||||
|
|
|
@ -121,6 +121,16 @@
|
|||
;------------------------
|
||||
;Setup RegTool
|
||||
|
||||
!ifdef NSIS_MAKENSIS64
|
||||
!if "${NSIS_PTR_SIZE}" < 8
|
||||
!error "Incompatible RegTool bitness, compile with 32-bit NSIS!" ; 64-bit RegTool on 32-bit Windows
|
||||
!endif
|
||||
!else
|
||||
!if "${NSIS_PTR_SIZE}" > 4
|
||||
!warning "Incompatible RegTool bitness!" ; 32-bit RegTool will probably fail to register 64-bit library
|
||||
!endif
|
||||
!endif
|
||||
|
||||
ReadRegStr $R3 HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" "${REGTOOL_KEY}"
|
||||
StrCpy $R3 $R3 -4 1
|
||||
IfFileExists $R3 +3
|
||||
|
|
|
@ -67,6 +67,16 @@ Example:
|
|||
;------------------------
|
||||
;Setup RegTool
|
||||
|
||||
!ifdef NSIS_MAKENSIS64
|
||||
!if "${NSIS_PTR_SIZE}" < 8
|
||||
!error "Incompatible RegTool bitness, compile with 32-bit NSIS!" ; 64-bit RegTool on 32-bit Windows
|
||||
!endif
|
||||
!else
|
||||
!if "${NSIS_PTR_SIZE}" > 4
|
||||
!warning "Incompatible RegTool bitness!" ; 32-bit RegTool will probably fail to register 64-bit library
|
||||
!endif
|
||||
!endif
|
||||
|
||||
ReadRegStr $R3 HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" "NSIS.Library.RegTool.v3"
|
||||
StrCpy $R3 $R3 -4 1
|
||||
IfFileExists $R3 +3
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue