Library improvements with lots of help from stb:

- InstallLib will register DLLs after reboot in the order they were specified in the script
 - InstallLib will register every DLL on reboot if the reboot flag is already set
 - rewrote RegTool in C
 - RegTool compiles from source code
 - RegTool will not run when double clicked
 - RegTool will register each DLL on a separate process to avoid conflicts


git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@4127 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
kichik 2005-06-23 11:24:11 +00:00
parent 01ea9d4bcb
commit 096373344d
5 changed files with 422 additions and 320 deletions

Binary file not shown.

View file

@ -0,0 +1,273 @@
#include <windows.h>
#define STR_SIZE 1024
void RunSelf(char cmd, char *file);
void RegDll(char *file);
void RegTypeLib(char *file);
void DeleteFileOnReboot(char *pszFile);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
char *cmdline;
char seekchar = ' ';
cmdline = GetCommandLine();
if (*cmdline == '\"')
seekchar = *cmdline++;
while (*cmdline && *cmdline != seekchar)
cmdline = CharNext(cmdline);
cmdline = CharNext(cmdline);
while (*cmdline == ' ')
cmdline++;
if (*cmdline++ != '/')
{
ExitProcess(1);
return 0;
}
if (*cmdline == 'S')
{
HKEY rootkey;
if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\NSIS.Library.RegTool.v2", 0, KEY_READ, &rootkey)))
{
char keyname[STR_SIZE];
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, "count", NULL, &t, (LPBYTE) &count, &l)) && t == REG_DWORD)
{
DWORD j;
char valname[128], mode[2], file[STR_SIZE];
for (j = 1; j <= count; j++)
{
wsprintf(valname, "%u.mode", j);
l = sizeof(mode);
if (FAILED(RegQueryValueEx(key, valname, NULL, &t, mode, &l)) || t != REG_SZ)
continue;
wsprintf(valname, "%u.file", j);
l = STR_SIZE;
if (FAILED(RegQueryValueEx(key, valname, NULL, &t, file, &l)) || t != REG_SZ)
continue;
RunSelf(mode[0], file);
}
}
RegCloseKey(key);
RegDeleteKey(rootkey, keyname);
}
}
RegCloseKey(rootkey);
RegDeleteKey(HKEY_LOCAL_MACHINE, "Software\\NSIS.Library.RegTool.v2");
}
{
char file[STR_SIZE];
if (GetModuleFileName(GetModuleHandle(NULL), file, STR_SIZE))
{
DeleteFileOnReboot(file);
}
}
}
else
{
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
OleInitialize(NULL);
if (*cmdline == 'D')
{
RegDll(cmdline + 1);
}
else if (*cmdline == 'T')
{
RegTypeLib(cmdline + 1);
}
OleUninitialize();
SetErrorMode(0);
}
ExitProcess(0);
return 0;
}
void RunSelf(char cmd, char *file)
{
char self[STR_SIZE];
char cmdline[STR_SIZE];
if (!*file || (cmd != 'D' && cmd != 'T'))
return;
if (GetModuleFileName(GetModuleHandle(NULL), self, STR_SIZE))
{
PROCESS_INFORMATION pi;
STARTUPINFO si = { sizeof(STARTUPINFO) };
wsprintf(cmdline, "\"%s\" /%c%s", self, cmd, file);
if (CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
}
}
}
void RegDll(char *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(char *file)
{
WCHAR wfile[STR_SIZE];
if (MultiByteToWideChar(CP_ACP, 0, file, -1, wfile, STR_SIZE) != 0)
{
ITypeLib* tlib;
if (SUCCEEDED(LoadTypeLib(wfile, &tlib))) {
RegisterTypeLib(tlib, wfile, NULL);
tlib->lpVtbl->Release(tlib);
}
}
}
char *mystrstri(char *a, char *b)
{
int l = lstrlen(b);
while (lstrlen(a) >= l)
{
char c = a[l];
a[l] = 0;
if (!lstrcmpi(a, b))
{
a[l] = c;
return a;
}
a[l] = c;
a = CharNext(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++;
}
}
void DeleteFileOnReboot(char *pszFile)
{
BOOL fOk = 0;
HMODULE hLib=GetModuleHandle("KERNEL32.dll");
if (hLib)
{
typedef BOOL (WINAPI *mfea_t)(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,DWORD dwFlags);
mfea_t mfea;
mfea=(mfea_t) GetProcAddress(hLib,"MoveFileExA");
if (mfea)
{
fOk=mfea(pszFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
}
}
if (!fOk)
{
static char szRenameLine[1024];
static char wininit[1024];
int cchRenameLine;
char *szRenameSec = "[Rename]\r\n";
HANDLE hfile, hfilemap;
DWORD dwFileSize, dwRenameLinePos;
int spn;
// wininit is used as a temporary here
spn = GetShortPathName(pszFile,wininit,1024);
if (!spn || spn > 1024)
return;
cchRenameLine = wsprintf(szRenameLine,"NUL=%s\r\n",wininit);
GetWindowsDirectory(wininit, 1024-16);
lstrcat(wininit, "\\wininit.ini");
hfile = CreateFile(wininit,
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hfile != INVALID_HANDLE_VALUE)
{
dwFileSize = GetFileSize(hfile, NULL);
hfilemap = CreateFileMapping(hfile, NULL, PAGE_READWRITE, 0, dwFileSize + cchRenameLine + 10, NULL);
if (hfilemap != NULL)
{
LPSTR pszWinInit = (LPSTR) MapViewOfFile(hfilemap, FILE_MAP_WRITE, 0, 0, 0);
if (pszWinInit != NULL)
{
LPSTR pszRenameSecInFile = mystrstri(pszWinInit, szRenameSec);
if (pszRenameSecInFile == NULL)
{
lstrcpy(pszWinInit+dwFileSize, szRenameSec);
dwFileSize += 10;
dwRenameLinePos = dwFileSize;
}
else
{
char *pszFirstRenameLine = pszRenameSecInFile+10;
char *pszNextSec = mystrstri(pszFirstRenameLine,"\n[");
if (pszNextSec)
{
char *p = ++pszNextSec;
while (p < pszWinInit + dwFileSize) {
p[cchRenameLine] = *p;
p++;
}
dwRenameLinePos = pszNextSec - pszWinInit;
}
// rename section is last, stick item at end of file
else dwRenameLinePos = dwFileSize;
}
mini_memcpy(&pszWinInit[dwRenameLinePos], szRenameLine, cchRenameLine);
dwFileSize += cchRenameLine;
UnmapViewOfFile(pszWinInit);
}
CloseHandle(hfilemap);
}
SetFilePointer(hfile, dwFileSize, NULL, FILE_BEGIN);
SetEndOfFile(hfile);
CloseHandle(hfile);
}
}
}

View file

@ -1,126 +0,0 @@
; RegTool
; Written by Joost Verburg
;
; This tool is used by the Library.nsh macros to register
; dynamic link libraries and type libraries after a reboot.
;--------------------------------
Name "RegTool"
OutFile "RegToolGenerator.exe"
SilentInstall silent
SilentUninstall silent
SetCompressor lzma
Icon "${NSISDIR}\Contrib\Graphics\Icons\classic-install.ico"
UninstallIcon "${NSISDIR}\Contrib\Graphics\Icons\classic-install.ico"
AllowRootDirInstall true
;--------------------------------
Var MODE
Var FILENAME
Var FOLDER
;--------------------------------
Section
WriteUninstaller $EXEDIR\RegTool.bin
SectionEnd
Section uninstall
StrCpy $0 -1
loop:
IntOp $0 $0 + 1
EnumRegValue $FILENAME HKLM "Software\NSIS.Library.RegTool" $0
StrCmp $FILENAME "" done
ReadRegStr $MODE HKLM "Software\NSIS.Library.RegTool" $FILENAME
StrCmp $MODE "DT" 0 +4
Call un.RegDLL
Call un.RegTLB
Goto loop
StrCmp $MODE "D" 0 +3
Call un.RegDLL
Goto loop
StrCmp $MODE "T" 0 +3
Call un.RegTLB
Goto loop
Goto loop
done:
DeleteRegKey HKLM "Software\NSIS.Library.RegTool"
Delete $INSTDIR\NSIS.Library.RegTool.exe
SectionEnd
Function un.RegDLL
Push $FILENAME
Call un.GetParent
Pop $FOLDER
SetOutPath $FOLDER
RegDLL $FILENAME
FunctionEnd
Function un.RegTLB
TypeLib::Register $FILENAME
FunctionEnd
; GetParent
; input, top of stack (e.g. C:\Program Files\Poop)
; output, top of stack (replaces, with e.g. C:\Program Files)
; modifies no other variables.
;
; Usage:
; Push "C:\Program Files\Directory\Whatever"
; Call GetParent
; Pop $R0
; ; at this point $R0 will equal "C:\Program Files\Directory"
Function un.GetParent
Exch $R0
Push $R1
Push $R2
Push $R3
StrCpy $R1 0
StrLen $R2 $R0
loop:
IntOp $R1 $R1 + 1
IntCmp $R1 $R2 get 0 get
StrCpy $R3 $R0 1 -$R1
StrCmp $R3 "\" get
Goto loop
get:
StrCpy $R0 $R0 -$R1
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd

View file

@ -7,13 +7,11 @@ files = Split("""
libs = Split("""
kernel32
oleaut32
version
advapi32
user32
ole32
""")
#Import('BuildUtil')
Import('BuildUtil')
#BuildUtil(target, files, libs, install = 'Bin')
Import('env')
env.Distribute('Bin', 'RegTool.bin')
BuildUtil(target, files, libs, entry = 'WinMain', nodeflib = 1, install_as = 'Bin/RegTool.bin')

View file

@ -1,153 +1,21 @@
/*
***********************
Macro - Install Library
***********************
This macro can be used to install DLL and TLB libraries. It checks for version numbers and Windows file protection,
registers the files and can update files on reboot.
To ask the user for a reboot if required, use the Modern UI with a Finish page or use IfRebootFlag and make your
own page or message box.
Usage:
!insertmacro InstallLib libtype shared install localfile destfile tempbasedir
Parameters:
libtype The type of the library
DLL Dynamic link library (DLL)
REGDLL DLL that has to be registered
TLB Type library or DLL that contains a type LIBRARY
REGDLLTLB DLL that has to be registered and contains a type library
shared Specify whether the library is shared with other applications
NOTSHARED The library is not shared
$VARNAME Variable that is empty when the application is installed for the first time,
which is when the shared library count will be increased.
install Specify the installation method
REBOOT_PROTECTED * Upgrade the library on reboot when in use (required for system files).
* Upgrade the library if the file is not protected by Windows File Protection.
NOREBOOT_PROTECTED * Warns the user when the library is in use. The user will have to close
applications using the library.
* Upgrade the library if the file is not protected by Windows File Protection.
REBOOT_NOTPROTECTED * Upgrade the library on reboot when in use (required for system files).
* Upgrade the library without checking for Windows File Protection.
NOREBOOT_NOTPROTECTED * Warns the user when the library is in use. The user will have to close
applications using the library.
* Upgrade the library without checking for Windows File Protection.
localfile Location of the library on the compiler system
destfile Location to store the library on the user's system
tempbasedir Directory on the user's system to store a temporary file when the system has
to be rebooted.
For Windows 9x/ME support, this directory should be on the same volume as the
destination file (destfile).
The Windows temp directory could be located on any volume, so you cannot use
this directory.
Options:
LIBRARY_SHELL_EXTENSION
Define this before inserting InstallLib macro to call SHChangeNotify with SHCNE_ASSOCCHANGED after registration. Use this to refresh the shell when installing a shell extension or when changing file associations.
LIBRARY_COM
Define this before inserting InstallLib macro to call CoFreeUnusedLibraries after registration. Use this for unloading all unnecessary libraries from memory when installing COM libraries.
Notes:
* If you want to support Windows 9x/ME, you can only use short filenames (8.3).
* You can only compile scripts using this macro on Windows systems.
------------------------
Example:
Var ALREADY_INSTALLED
;Add code here that sets $ALREADY_INSTALLED to a non-zero value if the application is
;already installed.
!insertmacro InstallLib REGDLL $ALREADY_INSTALLED REBOOT_NOTPROTECTED dllname.dll $SYSDIR\dllname.dll $SYSDIR
*************************
Macro - Uninstall Library
*************************
This macro can be used to uninstall DLL and TLB libraries. It unregisters files and can remove them on reboot.
Usage:
!insertmacro UnInstallLib libtype shared uninstall file
Parameters:
libtype The type of the library
DLL Dynamic link library (DLL)
REGDLL DLL that has to be registered
TLB Type library or DLL that contains a type LIBRARY
REGTLB DLL that has to be registered and contains a type library
shared Specify whether the library is shared with other applications
NOTSHARED The library is not shared
SHARE The library is shared and should be removed if the shared library count
indicates that the file is not in use anymore.
uninstall Specify the uninstallation method
NOREMOVE The library should not be removed.
You should use this option for common or important system files such as the
Visual Basic/C++/MFC runtimes.
REBOOT_PROTECTED * Remove the library on reboot when in use (required for system files).
* Remove the library if the file is not protected by Windows File Protection.
NOREBOOT_PROTECTED * Warns the user when the library is in use. The user will have to close
applications using the library.
* Remove the library if the file is not protected by Windows File Protection.
REBOOT_NOTPROTECTED * Remove the library on reboot when in use (required for system files).
* Remove the library without checking for Windows File Protection.
NOREBOOT_NOTPROTECTED * Warns the user when the library is in use. The user will have to close
applications using the library.
* Remove the library without checking for Windows File Protection.
file Location of the library
Options:
LIBRARY_SHELL_EXTENSION
Define this before inserting UninstallLib macro to call SHChangeNotify with SHCNE_ASSOCCHANGED after unregistration. Use this to refresh the shell when uninstalling a shell extension or when changing file associations.
LIBRARY_COM
Define this before inserting UninstallLib macro to call CoFreeUnusedLibraries after unregistration. Use this for unloading all unnecessary libraries from memory when uninstalling COM libraries.
------------------------
Example:
!insertmacro UnInstallLib REGDLL SHARED REBOOT_NOTPROTECTED $SYSDIR\dllname.dll
*/
#
# Library.nsh
#
# A system for the installation and uninstallation of dynamic
# link libraries (DLL) and type libraries (TLB). Using this
# system you can handle the complete setup with one single
# line of code:
#
# * File copying
# * File copying on reboot
# * Version checks
# * Registration and unregistration
# * Registration and unregistration on reboot
# * Shared DLL counting
# * Windows File Protection checks
#
# For more information, read appendix B in the documentation.
#
!ifndef LIB_INCLUDED
@ -160,10 +28,81 @@ Example:
!define SHCNF_IDLIST 0x0000
!endif
Var __INSTALLLLIB_SESSIONGUID
### Initialize session id (GUID)
!macro __InstallLib_Helper_InitSession
StrCmp $__INSTALLLLIB_SESSIONGUID '' 0 +6
System::Alloc 16
System::Call 'ole32::CoCreateGuid(i sR0)'
System::Call 'ole32::StringFromGUID2(i R0, w .s, i ${NSIS_MAX_STRLEN})'
System::Free $R0
Pop $__INSTALLLLIB_SESSIONGUID
StrCmp $__INSTALLLLIB_SESSIONGUID '' 0 +2
StrCpy $__INSTALLLLIB_SESSIONGUID 'session'
!macroend
### Add a RegTool entry to register after reboot
!macro __InstallLib_Helper_AddRegToolEntry mode filename tempdir
Push $R0
Push $R1
Push $R2
Push $R3
;------------------------
;Copy the parameters
Push "${filename}"
Push "${tempdir}"
Pop $R2 ; temporary directory
Pop $R1 ; file name to register
;------------------------
;Initialize session id
!insertmacro __InstallLib_Helper_InitSession
;------------------------
;Advance counter
StrCpy $R0 0
ReadRegDWORD $R0 HKLM "Software\NSIS.Library.RegTool.v2\$__INSTALLLLIB_SESSIONGUID" "count"
IntOp $R0 $R0 + 1
WriteRegDWORD HKLM "Software\NSIS.Library.RegTool.v2\$__INSTALLLLIB_SESSIONGUID" "count" "$R0"
;------------------------
;Setup RegTool
ReadRegStr $R3 HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" "NSIS.Library.RegTool.v2"
IfFileExists $R3 +3
File /oname=$R2\NSIS.Library.RegTool.v2.exe "${NSISDIR}\Bin\RegTool.bin"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" \
"NSIS.Library.RegTool.v2" '"$R2\NSIS.Library.RegTool.v2.exe" /S'
;------------------------
;Add RegTool entry
WriteRegStr HKLM "Software\NSIS.Library.RegTool.v2\$__INSTALLLLIB_SESSIONGUID" "$R0.file" "$R1"
WriteRegStr HKLM "Software\NSIS.Library.RegTool.v2\$__INSTALLLLIB_SESSIONGUID" "$R0.mode" "${mode}"
Pop $R2
Pop $R1
Pop $R0
!macroend
### Install library
!macro InstallLib libtype shared install localfile destfile tempbasedir
!verbose push
!verbose 3
#!verbose 3
Push $R0
Push $R1
@ -402,36 +341,7 @@ Example:
;------------------------
;Register on reboot
!ifdef INSTALLLIB_LIBTYPE_REGDLL | INSTALLLIB_LIBTYPE_TLB | INSTALLLIB_LIBTYPE_REGDLLTLB
ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" "NSIS.Library.RegTool"
IfFileExists $R0 installlib.rebootreg_${INSTALLLIB_UNIQUE}
File /oname=$R5\NSIS.Library.RegTool.exe "${NSISDIR}\Bin\RegTool.bin"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" \
"NSIS.Library.RegTool" '"$R5\NSIS.Library.RegTool.exe"'
installlib.rebootreg_${INSTALLLIB_UNIQUE}:
!endif
!ifdef INSTALLLIB_LIBTYPE_REGDLL
WriteRegStr HKLM "Software\NSIS.Library.RegTool" "$R4" 'D'
!endif
!ifdef INSTALLLIB_LIBTYPE_TLB
WriteRegStr HKLM "Software\NSIS.Library.RegTool" "$R4" 'T'
!endif
!ifdef INSTALLLIB_LIBTYPE_REGDLLTLB
WriteRegStr HKLM "Software\NSIS.Library.RegTool" "$R4" 'DT'
!endif
Call :installlib.regonreboot_${INSTALLLIB_UNIQUE}
Goto installlib.done_${INSTALLLIB_UNIQUE}
@ -452,15 +362,37 @@ Example:
!endif
!ifdef INSTALLLIB_LIBTYPE_REGDLL | INSTALLLIB_LIBTYPE_REGDLLTLB
!ifdef INSTALLLIB_LIBTYPE_REGDLL | INSTALLLIB_LIBTYPE_TLB | INSTALLLIB_LIBTYPE_REGDLLTLB
RegDLL $R4
!ifdef INSTALLLIB_INSTALL_REBOOT_PROTECTED | INSTALLLIB_INSTALL_REBOOT_NOTPROTECTED
!endif
IfRebootFlag 0 installlib.regnoreboot_${INSTALLLIB_UNIQUE}
!ifdef INSTALLLIB_LIBTYPE_TLB | INSTALLLIB_LIBTYPE_REGDLLTLB
Call :installlib.regonreboot_${INSTALLLIB_UNIQUE}
TypeLib::Register $R4
Goto installlib.registerfinish_${INSTALLLIB_UNIQUE}
installlib.regnoreboot_${INSTALLLIB_UNIQUE}:
!endif
!ifdef INSTALLLIB_LIBTYPE_TLB | INSTALLLIB_LIBTYPE_REGDLLTLB
TypeLib::Register $R4
!endif
!ifdef INSTALLLIB_LIBTYPE_REGDLL | INSTALLLIB_LIBTYPE_REGDLLTLB
RegDll $R4
!endif
!ifdef INSTALLLIB_INSTALL_REBOOT_PROTECTED | INSTALLLIB_INSTALL_REBOOT_NOTPROTECTED
installlib.registerfinish_${INSTALLLIB_UNIQUE}:
!endif
!endif
@ -483,7 +415,7 @@ Example:
!undef LIBRARY_DEFINE_DONE_LABEL
installlib.done_${INSTALLLIB_UNIQUE}:
installlib.done_${INSTALLLIB_UNIQUE}:
!endif
@ -528,6 +460,30 @@ Example:
!endif
;------------------------
;Register on reboot
!ifdef INSTALLLIB_INSTALL_REBOOT_PROTECTED | INSTALLLIB_INSTALL_REBOOT_NOTPROTECTED
installlib.regonreboot_${INSTALLLIB_UNIQUE}:
!ifdef INSTALLLIB_LIBTYPE_REGDLL
!insertmacro __InstallLib_Helper_AddRegToolEntry 'D' "$R4" "$R5"
!endif
!ifdef INSTALLLIB_LIBTYPE_TLB
!insertmacro __InstallLib_Helper_AddRegToolEntry 'T' "$R4" "$R5"
!endif
!ifdef INSTALLLIB_LIBTYPE_REGDLLTLB
!insertmacro __InstallLib_Helper_AddRegToolEntry 'D' "$R4" "$R5"
!insertmacro __InstallLib_Helper_AddRegToolEntry 'T' "$R4" "$R5"
!endif
Return
!endif
;------------------------
;Undefine
@ -544,6 +500,7 @@ Example:
!macroend
### Uninstall library
!macro UnInstallLib libtype shared uninstall file
!verbose push