1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
|
// RegTool v3
// Unicode support by Jim Park & Olivier Marcoux
#include "../../../Source/Platform.h"
#include <windows.h>
#define STR_SIZE 1024
#if defined(_MSC_VER) && _MSC_VER-0 >= 1600 && _MSC_VER-0 <= 1800 // MSVC complains about math stuff we are not even using (bug #1159)
EXTERN_C int _fltused = 0;
EXTERN_C double _hypot(double x, double y) { return 0.0; }
#endif
/*
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); }
}
#if defined(_MSC_VER) && _MSC_VER >= 1200
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ( (HINSTANCE) &__ImageBase )
#define HINST_APPLICATION HINST_THISCOMPONENT
#else
#define HINST_APPLICATION ( (HINSTANCE) GetModuleHandle(NULL) )
#endif
static bool IsWinNT()
{
#if defined(_WIN64) || (defined(_M_ARM) || defined(__arm__))
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)(HINST_APPLICATION, 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)(HINST_APPLICATION, 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);
}
|