UpgradeDLL Func function
From NSIS Wiki
Jump to navigationJump to search
Author: opher (talk, contrib) |
Description
In my setup package I had to install 64 system files, which meant 64 !insertmacro UpgradeDLL ... lines :'( So I wrote this function. It is capable of accepting a source directory (e.g. "$PLUGINSDIR\SysFiles") and a destination directory (e.g. $SYSDIR) and installing/upgrading all files in source with *one* function call. :)
Requires Get extention of file
The Function
!ifndef UPGRADEDLL_FUNC_INCLUDED !define UPGRADEDLL_FUNC_INCLUDED ; Function - Upgrade DLL File ; Written by Opher Shachar on 2004/01/14 ; Revised on 2004/01/15: Supports registering *.TLB, *.OLB files with 'regtlib.exe' ; Needs 'GetFileExt' (http://nsis.sourceforge.net/wiki/Get_extention_of_file) ; Revised 2007/02/06: fix directory as source, skip '.' and '..' entries ; $R6 now is VOLATILE ; Based on macro by Joost Verburg ; -------------------------------------- ; ; Parameters: ; $R4 = DESTFILE - Location of the DLL file that should be upgraded (on user's system) ; OR DESTDIR - Target directory for upgraded DLLs ; $R5 = TEMPBASEDIR - Directory on the user's system to store a temporary file when ; the system has to be rebooted. ; For Win9x support, this should be on the same volume as the DESTFILE! ; The Windows temp directory could be located on any volume, so you cannot ; use this directory. ; $R6 = REGISTER - if you want to upgrade a DLL that has to be registered. ; 0 = Don't register, anything else = Register -- note: VOLATILE ; $R7 = LOCALFILE - Location of the new DLL file (on the user's system) ; OR LOCALDIR - Source directory of newer DLLs ; Note: If you want to support Win9x, you can only use short filenames (8.3). ; ; Example of usage for single file: ; $R4 = "$SYSDIR\dllname.dll" ; $R5 = "$SYSDIR" ; $R6 = "1" (= Register DLL) ; $R7 = "Source_dir\dllname.dll" ; Call UpgradeDLL_Func ; ; Example of usage with File command: ; SetOutPath "$PLUGINSDIR\SysFiles" ; File /r "sys_files_to_be_installed\*.*" ... ; ... ; File "some_other_sys_file.dll" ; $R4 = "$SYSDIR" -- note no '\', MUST be an existing directory ; $R5 = "$SYSDIR" ; $R6 = "1" (= Register DLL) ; $R7 = "$PLUGINSDIR\SysFiles" -- note no '\' ; Call UpgradeDLL_Func ; RMDir /r "$PLUGINSDIR\SysFiles" ; ; Example of usage for whole bunch of external files: ; $R4 = "$SYSDIR" -- note no '\', MUST be an existing directory ; $R5 = "$SYSDIR" ; $R6 = "1" (= Register DLL) ; $R7 = "Source_dir" -- note no '\' ; Call UpgradeDLL_Func Function UpgradeDLL_Func Push $R0 Push $R1 Push $R2 Push $R3 SetOverwrite try ;------------------------ ;Check single file IfFileExists "$R7\*.*" +3 Call :upgradedll.doit Goto upgradedll.end ;------------------------ ;Enumerate directory Push $0 Push $1 Push $2 StrCpy $1 $R7 StrCpy $2 $R4 FindFirst $0 $R0 "$1\*.*" loop: IfErrors upgradedll.nomore StrCpy $R7 "$1\$R0" StrCpy $R4 "$2\$R0" StrCmp $R0 "." +3 StrCmp $R0 ".." +2 Call :upgradedll.doit FindNext $0 $R0 Goto loop upgradedll.nomore: FindClose $0 StrCpy $R7 $1 StrCpy $R4 $2 Pop $2 Pop $1 Pop $0 Goto upgradedll.end ;------------------------ ;Do we want to register file? upgradedll.doit: IntCmp $R6 0 upgradedll.moveon ;------------------------ ;Is file a .TLB? == Use 'regtlib.exe' instead of 'RegDLL' Push $R4 Call GetFileExt Pop $R0 StrCmp $R0 "TLB" +2 StrCmp $R0 "OLB" 0 +3 StrCpy $R6 -1 Goto upgradedll.moveon StrCpy $R6 1 ;------------------------ ;File already installed? No. Just copy upgradedll.moveon: IfFileExists $R4 0 upgradedll.copy ;------------------------ ;Check file and version ClearErrors GetDLLVersion $R7 $R0 $R1 GetDLLVersion $R4 $R2 $R3 IfErrors upgradedll.upgrade IntCmpU $R0 $R2 0 upgradedll.done upgradedll.upgrade IntCmpU $R1 $R3 upgradedll.noreboot upgradedll.done upgradedll.upgrade ;------------------------ ;Let's upgrade the DLL! upgradedll.upgrade: IntCmp $R6 1 0 +2 +2 UnRegDLL $R4 ;Unregister the DLL ;------------------------ ;Try to copy the DLL directly upgradedll.copy: ClearErrors StrCpy $R0 $R4 Call :upgradedll.file IfErrors 0 upgradedll.noreboot ;------------------------ ;DLL is in use. Copy it to a temp file and Rename it on reboot. GetTempFileName $R0 $R5 Call :upgradedll.file Rename /REBOOTOK $R0 $R4 ;------------------------ ;Register the DLL on reboot IntCmp $R6 0 upgradedll.done IntCmp $R6 1 +3 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" \ "Register $R4" '"$SYSDIR\regtlib.exe" "$R4"' Goto upgradedll.done WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" \ "Register $R4" '"$SYSDIR\rundll32.exe" "$R4",DllRegisterServer' Goto upgradedll.done ;------------------------ ;Register the DLL upgradedll.noreboot: IntCmp $R6 0 upgradedll.done IntCmp $R6 1 +3 ExecWait '"$SYSDIR\regtlib.exe" "$R4"' Goto upgradedll.done RegDLL $R4 ;------------------------ ;Done upgradedll.done: Return ;------------------------ ;Called to copy the DLL upgradedll.file: CopyFiles /silent $R7 $R0 Return ;------------------------ ;End upgradedll.end: Pop $R3 Pop $R2 Pop $R1 Pop $R0 ;------------------------ ;Restore settings SetOverwrite lastused FunctionEnd !endif