\A{usefulfunctions} Useful Functions

\H{getparent} Get parent directory

\c  ; GetParent
\c  ; input, top of stack  (e.g. C:\Program Files\Poop)
\c  ; output, top of stack (replaces, with e.g. C:\Program Files)
\c  ; modifies no other variables.
\c  ;
\c  ; Usage:
\c  ;   Push "C:\Program Files\Directory\Whatever"
\c  ;   Call GetParent
\c  ;   Pop $R0
\c  ;   ; at this point $R0 will equal "C:\Program Files\Directory"
\c
\c  Function GetParent
\c  
\c    Exch $R0
\c    Push $R1
\c    Push $R2
\c    Push $R3
\c    
\c    StrCpy $R1 0
\c    StrLen $R2 $R0
\c    
\c    loop:
\c      IntOp $R1 $R1 + 1
\c      IntCmp $R1 $R2 get 0 get
\c      StrCpy $R3 $R0 1 -$R1
\c      StrCmp $R3 "\" get
\c      Goto loop
\c    
\c    get:
\c      StrCpy $R0 $R0 -$R1
\c      
\c      Pop $R3
\c      Pop $R2
\c      Pop $R1
\c      Exch $R0
\c      
\c  FunctionEnd

\H{trimnewlines} Trim newlines

\c  ; TrimNewlines
\c  ; input, top of stack  (e.g. whatever$\r$\n)
\c  ; output, top of stack (replaces, with e.g. whatever)
\c  ; modifies no other variables.
\c
\c  Function TrimNewlines
\c    Exch $R0
\c    Push $R1
\c    Push $R2
\c    StrCpy $R1 0
\c  
\c  loop:
\c    IntOp $R1 $R1 - 1
\c    StrCpy $R2 $R0 1 $R1
\c    StrCmp $R2 "$\r" loop
\c    StrCmp $R2 "$\n" loop
\c    IntOp $R1 $R1 + 1
\c    IntCmp $R1 0 no_trim_needed
\c    StrCpy $R0 $R0 $R1
\c  
\c  no_trim_needed:
\c    Pop $R2
\c    Pop $R1
\c    Exch $R0
\c  FunctionEnd


\H{getparameters} Get command line parameters

\c  ; GetParameters
\c  ; input, none
\c  ; output, top of stack (replaces, with e.g. whatever)
\c  ; modifies no other variables.
\c  
\c  Function GetParameters
\c  
\c    Push $R0
\c    Push $R1
\c    Push $R2
\c    Push $R3
\c    
\c    StrCpy $R2 1
\c    StrLen $R3 $CMDLINE
\c    
\c    ;Check for quote or space
\c    StrCpy $R0 $CMDLINE $R2
\c    StrCmp $R0 '"' 0 +3
\c      StrCpy $R1 '"'
\c      Goto loop
\c    StrCpy $R1 " "
\c    
\c    loop:
\c      IntOp $R2 $R2 + 1
\c      StrCpy $R0 $CMDLINE 1 $R2
\c      StrCmp $R0 $R1 get
\c      StrCmp $R2 $R3 get
\c      Goto loop
\c    
\c    get:
\c      IntOp $R2 $R2 + 1
\c      StrCpy $R0 $CMDLINE 1 $R2
\c      StrCmp $R0 " " get
\c      StrCpy $R0 $CMDLINE "" $R2
\c    
\c    Pop $R3
\c    Pop $R2
\c    Pop $R1
\c    Exch $R0
\c  
\c  FunctionEnd

\H{strstr} Search in a string

\c  ; StrStr
\c  ; input, top of stack = string to search for
\c  ;        top of stack-1 = string to search in
\c  ; output, top of stack (replaces with the portion of the string remaining)
\c  ; modifies no other variables.
\c  ;
\c  ; Usage:
\c  ;   Push "this is a long ass string"
\c  ;   Push "ass"
\c  ;   Call StrStr
\c  ;   Pop $R0
\c  ;  ($R0 at this point is "ass string")
\c
\c  Function StrStr
\c    Exch $R1 ; st=haystack,old$R1, $R1=needle
\c    Exch    ; st=old$R1,haystack
\c    Exch $R2 ; st=old$R1,old$R2, $R2=haystack
\c    Push $R3
\c    Push $R4
\c    Push $R5
\c    StrLen $R3 $R1
\c    StrCpy $R4 0
\c    ; $R1=needle
\c    ; $R2=haystack
\c    ; $R3=len(needle)
\c    ; $R4=cnt
\c    ; $R5=tmp
\c    loop:
\c      StrCpy $R5 $R2 $R3 $R4
\c      StrCmp $R5 $R1 done
\c      StrCmp $R5 "" done
\c      IntOp $R4 $R4 + 1
\c      Goto loop
\c  done:
\c    StrCpy $R1 $R2 "" $R4
\c    Pop $R5
\c    Pop $R4
\c    Pop $R3
\c    Pop $R2
\c    Exch $R1
\c  FunctionEnd

\H{getwindowsversion} Get Windows version

\c  ; GetWindowsVersion
\c  ;
\c  ; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/
\c  ; Updated by Joost Verburg
\c  ;
\c  ; Returns on top of stack
\c  ;
\c  ; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003)
\c  ; or
\c  ; '' (Unknown Windows Version)
\c  ;
\c  ; Usage:
\c  ;   Call GetWindowsVersion
\c  ;   Pop $R0
\c  ;   ; at this point $R0 is "NT 4.0" or whatnot
\c  
\c  Function GetWindowsVersion
\c  
\c    Push $R0
\c    Push $R1
\c  
\c    ReadRegStr $R0 HKLM \
\c    "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
\c
\c    IfErrors 0 lbl_winnt
\c    
\c    ; we are not NT
\c    ReadRegStr $R0 HKLM \
\c    "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber
\c  
\c    StrCpy $R1 $R0 1
\c    StrCmp $R1 '4' 0 lbl_error
\c  
\c    StrCpy $R1 $R0 3
\c  
\c    StrCmp $R1 '4.0' lbl_win32_95
\c    StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98
\c  
\c    lbl_win32_95:
\c      StrCpy $R0 '95'
\c    Goto lbl_done
\c  
\c    lbl_win32_98:
\c      StrCpy $R0 '98'
\c    Goto lbl_done
\c  
\c    lbl_win32_ME:
\c      StrCpy $R0 'ME'
\c    Goto lbl_done
\c  
\c    lbl_winnt:
\c  
\c    StrCpy $R1 $R0 1
\c  
\c    StrCmp $R1 '3' lbl_winnt_x
\c    StrCmp $R1 '4' lbl_winnt_x
\c  
\c    StrCpy $R1 $R0 3
\c  
\c    StrCmp $R1 '5.0' lbl_winnt_2000
\c    StrCmp $R1 '5.1' lbl_winnt_XP
\c    StrCmp $R1 '5.2' lbl_winnt_2003 lbl_error
\c  
\c    lbl_winnt_x:
\c      StrCpy $R0 "NT $R0" 6
\c    Goto lbl_done
\c  
\c    lbl_winnt_2000:
\c      Strcpy $R0 '2000'
\c    Goto lbl_done
\c  
\c    lbl_winnt_XP:
\c      Strcpy $R0 'XP'
\c    Goto lbl_done
\c  
\c    lbl_winnt_2003:
\c      Strcpy $R0 '2003'
\c    Goto lbl_done
\c  
\c    lbl_error:
\c      Strcpy $R0 ''
\c    lbl_done:
\c  
\c    Pop $R1
\c    Exch $R0
\c  
\c  FunctionEnd


\H{getieversion} Get Internet Explorer version

\c  ; GetIEVersion
\c  ;
\c  ; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/
\c  ; Returns on top of stack
\c  ; 1-6 (Installed IE Version)
\c  ; or
\c  ; '' (IE is not installed)
\c  ;
\c  ; Usage:
\c  ;   Call GetIEVersion
\c  ;   Pop $R0
\c  ;   ; at this point $R0 is "5" or whatnot
\c
\c  Function GetIEVersion
\c  Push $R0
\c    ClearErrors
\c    ReadRegStr $R0 HKLM "Software\Microsoft\Internet Explorer" "Version"
\c    IfErrors lbl_123 lbl_456
\c
\c    lbl_456: ; ie 4+
\c      Strcpy $R0 $R0 1
\c    Goto lbl_done
\c
\c    lbl_123: ; older ie version
\c      ClearErrors
\c      ReadRegStr $R0 HKLM "Software\Microsoft\Internet Explorer" "IVer"
\c      IfErrors lbl_error
\c
\c        StrCpy $R0 $R0 3
\c        StrCmp $R0 '100' lbl_ie1
\c        StrCmp $R0 '101' lbl_ie2
\c        StrCmp $R0 '102' lbl_ie2
\c
\c        StrCpy $R0 '3' ; default to ie3 if not 100, 101, or 102.
\c        Goto lbl_done
\c          lbl_ie1:
\c            StrCpy $R0 '1'
\c          Goto lbl_done
\c          lbl_ie2:
\c            StrCpy $R0 '2'
\c          Goto lbl_done
\c      lbl_error:
\c        StrCpy $R0 ''
\c    lbl_done:
\c    Exch $R0
\c  FunctionEnd

\H{detect.netframework} Is .NET Framework installed?

\c  ; IsDotNETInstalled
\c  ;
\c  ; Usage:
\c  ;   Call IsDotNETInstalled
\c  ;   Pop $0
\c  ;   StrCmp $0 1 found.NETFramework no.NETFramework
\c
\c  Function IsDotNETInstalled
\c    Push $0
\c    Push $1
\c    Push $2
\c    Push $3
\c    Push $4
\c
\c    ReadRegStr $4 HKEY_LOCAL_MACHINE \
\c      "Software\Microsoft\.NETFramework" "InstallRoot"
\c    # remove trailing back slash
\c    Push $4
\c    Exch $EXEDIR
\c    Exch $EXEDIR
\c    Pop $4
\c    # if the root directory doesn't exist .NET is not installed
\c    IfFileExists $4 0 noDotNET
\c
\c    StrCpy $0 0
\c
\c    EnumStart:
\c
\c      EnumRegKey $2 HKEY_LOCAL_MACHINE \
\c        "Software\Microsoft\.NETFramework\Policy"  $0
\c      IntOp $0 $0 + 1
\c      StrCmp $2 "" noDotNET
\c
\c      StrCpy $1 0
\c
\c      EnumPolicy:
\c
\c        EnumRegValue $3 HKEY_LOCAL_MACHINE \
\c          "Software\Microsoft\.NETFramework\Policy\$2" $1
\c        IntOp $1 $1 + 1
\c         StrCmp $3 "" EnumStart
\c          IfFileExists "$4\$2.$3" foundDotNET EnumPolicy
\c
\c    noDotNET:
\c      StrCpy $0 0
\c      Goto done
\c
\c    foundDotNET:
\c      StrCpy $0 1
\c
\c    done:
\c      Pop $4
\c      Pop $3
\c      Pop $2
\c      Pop $1
\c      Exch $0
\c  FunctionEnd

\H{isflashinstalled} Is Macromedia Flash Player installed?

\c  ; IsFlashInstalled
\c  ;
\c  ; By Yazno, http://yazno.tripod.com/powerpimpit/
\c  ; Returns on top of stack
\c  ; 0 (Flash is not installed)
\c  ; or
\c  ; 1 (Flash is installed)
\c  ;
\c  ; Usage:
\c  ;   Call IsFlashInstalled
\c  ;   Pop $R0
\c  ;   ; $R0 at this point is "1" or "0"
\c
\c  Function IsFlashInstalled
\c   Push $R0
\c   ClearErrors
\c   ReadRegStr $R0 HKCR "CLSID\{D27CDB6E-AE6D-11cf-96B8-444553540000}" ""
\c   IfErrors lbl_na
\c     StrCpy $R0 1
\c   Goto lbl_end
\c   lbl_na:
\c     StrCpy $R0 0
\c   lbl_end:
\c   Exch $R0
\c  FunctionEnd

\H{addshareddll} Add a shared DLL

\c  ; AddSharedDLL
\c  ;
\c  ; Increments a shared DLLs reference count.
\c  ; Use by passing one item on the stack (the full path of the DLL).
\c  ;
\c  ; Usage:
\c  ;   Push $SYSDIR\myDll.dll
\c  ;   Call AddSharedDLL
\c  ;
\c
\c  Function AddSharedDLL
\c    Exch $R1
\c    Push $R0
\c    ReadRegDword $R0 HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1
\c    IntOp $R0 $R0 + 1
\c    WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1 $R0
\c    Pop $R0
\c    Pop $R1
\c  FunctionEnd

\H{unremovesharedll} Remove a shared DLL

\c  ; un.RemoveSharedDLL
\c  ;
\c  ; Decrements a shared DLLs reference count, and removes if necessary.
\c  ; Use by passing one item on the stack (the full path of the DLL).
\c  ; Note: for use in the main installer (not the uninstaller), rename the
\c  ; function to RemoveSharedDLL.
\c  ;
\c  ; Usage:
\c  ;   Push $SYSDIR\myDll.dll
\c  ;   Call un.RemoveSharedDLL
\c  ;
\c
\c  Function un.RemoveSharedDLL
\c    Exch $R1
\c    Push $R0
\c    ReadRegDword $R0 HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1
\c    StrCmp $R0 "" remove
\c      IntOp $R0 $R0 - 1
\c      IntCmp $R0 0 rk rk uk
\c      rk:
\c        DeleteRegValue HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1
\c      goto Remove
\c      uk:
\c        WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1 $R0
\c      Goto noremove
\c    remove:
\c      Delete /REBOOTOK $R1
\c    noremove:
\c    Pop $R0
\c    Pop $R1
\c  FunctionEnd

\H{upgradedll} Upgrade a DLL (macro)

There is also a copy of this macro in the Include folder, so you only have to include UpgradeDLL.nsh to use it.

\c ; Macro - Upgrade DLL File
\c ; Written by Joost Verburg
\c ; ------------------------
\c ;
\c ; Parameters:
\c ; LOCALFILE   - Location of the new DLL file (on the compiler system)
\c ; DESTFILE    - Location of the DLL file that should be upgraded (on the user's system)
\c ; TEMPBASEDIR - Directory on the user's system to store a temporary file when the system has
\c ;               to be rebooted.
\c ;               For Win9x support, this should be on the same volume as the DESTFILE!
\c ;               The Windows temp directory could be located on any volume, so you cannot use
\c ;               this directory.
\c ;
\c ; Define UPGRADEDLL_NOREGISTER if you want to upgrade a DLL that does not have to be registered.
\c ;
\c ; Note: If you want to support Win9x, you can only use short filenames (8.3).
\c ;
\c ; Example of usage:
\c ; !insertmacro UpgradeDLL "dllname.dll" "$SYSDIR\dllname.dll" "$SYSDIR"
\c ;
\c
\c !macro UpgradeDLL LOCALFILE DESTFILE TEMPBASEDIR
\c
\c   Push $R0
\c   Push $R1
\c   Push $R2
\c   Push $R3
\c   Push $R4
\c   Push $R5
\c
\c   ;------------------------
\c   ;Unique number for labels
\c
\c   !define UPGRADEDLL_UNIQUE ${__LINE__}
\c
\c   ;------------------------
\c   ;Copy the parameters used on run-time to a variable
\c   ;This allows the usage of variables as paramter
\c
\c   StrCpy $R4 "${DESTFILE}"
\c   StrCpy $R5 "${TEMPBASEDIR}"
\c
\c   ;------------------------
\c   ;Check file and version
\c
\c   IfFileExists $R4 0 upgradedll.copy_${UPGRADEDLL_UNIQUE}
\c
\c   ClearErrors
\c     GetDLLVersionLocal "${LOCALFILE}" $R0 $R1
\c     GetDLLVersion $R4 $R2 $R3
\c   IfErrors upgradedll.upgrade_${UPGRADEDLL_UNIQUE}
\c
\c   IntCmpU $R0 $R2 0 upgradedll.done_${UPGRADEDLL_UNIQUE} upgradedll.upgrade_${UPGRADEDLL_UNIQUE}
\c   IntCmpU $R1 $R3 upgradedll.done_${UPGRADEDLL_UNIQUE} upgradedll.done_${UPGRADEDLL_UNIQUE} \
\c     upgradedll.upgrade_${UPGRADEDLL_UNIQUE}
\c
\c   ;------------------------
\c   ;Let's upgrade the DLL!
\c
\c   SetOverwrite try
\c
\c   upgradedll.upgrade_${UPGRADEDLL_UNIQUE}:
\c     !ifndef UPGRADEDLL_NOREGISTER
\c       ;Unregister the DLL
\c       UnRegDLL $R4
\c     !endif
\c
\c   ;------------------------
\c   ;Try to copy the DLL directly
\c
\c   ClearErrors
\c     StrCpy $R0 $R4
\c     Call :upgradedll.file_${UPGRADEDLL_UNIQUE}
\c   IfErrors 0 upgradedll.noreboot_${UPGRADEDLL_UNIQUE}
\c
\c   ;------------------------
\c   ;DLL is in use. Copy it to a temp file and Rename it on reboot.
\c
\c   GetTempFileName $R0 $R5
\c     Call :upgradedll.file_${UPGRADEDLL_UNIQUE}
\c   Rename /REBOOTOK $R0 $R4
\c
\c   ;------------------------
\c   ;Register the DLL on reboot
\c
\c   !ifndef UPGRADEDLL_NOREGISTER
\c     WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" \
\c       "Register $R4" 'rundll32.exe "$R4",DllRegisterServer'
\c   !endif
\c
\c   Goto upgradedll.done_${UPGRADEDLL_UNIQUE}
\c
\c   ;------------------------
\c   ;DLL does not exist - just extract
\c
\c   upgradedll.copy_${UPGRADEDLL_UNIQUE}:
\c     StrCpy $R0 $R4
\c     Call :upgradedll.file_${UPGRADEDLL_UNIQUE}
\c
\c   ;------------------------
\c   ;Register the DLL
\c
\c   upgradedll.noreboot_${UPGRADEDLL_UNIQUE}:
\c     !ifndef UPGRADEDLL_NOREGISTER
\c       RegDLL $R4
\c     !endif
\c
\c   ;------------------------
\c   ;Done
\c
\c   upgradedll.done_${UPGRADEDLL_UNIQUE}:
\c
\c   Pop $R5
\c   Pop $R4
\c   Pop $R3
\c   Pop $R2
\c   Pop $R1
\c   Pop $R0
\c
\c   ;------------------------
\c   ;End
\c
\c   Goto upgradedll.end_${UPGRADEDLL_UNIQUE}
\c
\c   ;------------------------
\c   ;Called to extract the DLL
\c
\c   upgradedll.file_${UPGRADEDLL_UNIQUE}:
\c     File /oname=$R0 "${LOCALFILE}"
\c     Return
\c
\c   upgradedll.end_${UPGRADEDLL_UNIQUE}:
\c
\c  ;------------------------
\c  ;Restore settings
\c
\c  SetOverwrite lastused
\c  
\c  !undef UPGRADEDLL_UNIQUE
\c
\c !macroend

\H{connectinternet} Connect to the internet

\c  ; ConnectInternet (uses Dialer plugin)
\c  ; Written by Joost Verburg 
\c  ;
\c  ; This function attempts to make a connection to the internet if there is no
\c  ; connection available. If you are not sure that a system using the installer
\c  ; has an active internet connection, call this function before downloading
\c  ; files with NSISdl.
\c  ; 
\c  ; The function requires Internet Explorer 3, but asks to connect manually if
\c  ; IE3 is not installed.
\c  
\c  Function ConnectInternet
\c  
\c    Push $R0
\c      
\c      ClearErrors
\c      Dialer::AttemptConnect
\c      IfErrors noie3
\c      
\c      Pop $R0
\c      StrCmp $R0 "online" connected
\c        MessageBox MB_OK|MB_ICONSTOP "Cannot connect to the internet."
\c        Quit ;This will quit the installer. You might want to add your own error handling.
\c      
\c      noie3:
\c    
\c      ; IE3 not installed
\c      MessageBox MB_OK|MB_ICONINFORMATION "Please connect to the internet now."
\c      
\c      connected:
\c    
\c    Pop $R0
\c    
\c  FunctionEnd

\H{morefuncs} More

You can find more useful functions at \W{http://nsis.sourceforge.net/archive/}{the NSIS Archive}, \W{http://forums.winamp.com/forumdisplay.php?s=&forumid=65}{the NSIS forum} and \W{http://nsis.sourceforge.net/}{NSIS development page}.