NSIS utility functions

Contents:


General utility:
;------------------------------------------------------------------------------
; GetParent
; input, top of stack  (i.e. C:\Program Files\Poop)
; output, top of stack (replaces, with i.e. C:\Program Files)
; modifies no other variables.
;
; Usage:
;   Push "C:\Program Files\Directory\Whatever"
;   Call GetParent
;   Pop $0
;   ; at this point $0 will equal "C:\Program Files\Directory"


Function GetParent 
  Exch $0 ; old $0 is on top of stack
  Push $1
  Push $2
  StrCpy $1 -1
  loop:
    StrCpy $2 $0 1 $1
    StrCmp $2 "" exit
    StrCmp $2 "\" exit
    IntOp $1 $1 - 1
  Goto loop
  exit:
    StrCpy $0 $0 $1
    Pop $2
    Pop $1
    Exch $0 ; put $0 on top of stack, restore $0 to original value
FunctionEnd

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



;------------------------------------------------------------------------------
; GetParameters
; input, none
; output, top of stack (replaces, with i.e. whatever)
; modifies no other variables.

Function GetParameters
  Push $0
  Push $1
  Push $2
  StrCpy $0 $CMDLINE 1
  StrCpy $1 '"'
  StrCpy $2 1
  StrCmp $0 '"' loop
    StrCpy $1 ' ' ; we're scanning for a space instead of a quote
  loop:
    StrCpy $0 $CMDLINE 1 $2
    StrCmp $0 $1 loop2
    StrCmp $0 "" loop2
    IntOp $2 $2 + 1
    Goto loop
  loop2:
    IntOp $2 $2 + 1
    StrCpy $0 $CMDLINE 1 $2
    StrCmp $0 " " loop2
  StrCpy $0 $CMDLINE "" $2
  Pop $2
  Pop $1
  Exch $0
FunctionEnd

;------------------------------------------------------------------------------
; StrStr
; input, top of stack = string to search for
;        top of stack-1 = string to search in
; output, top of stack (replaces with the portion of the string remaining)
; modifies no other variables.
;
; Usage:
;   Push "this is a long ass string"
;   Push "ass"
;   Call StrStr
;   Pop $0
;  ($0 at this point is "ass string")

Function StrStr
  Exch $1 ; st=haystack,old$1, $1=needle
  Exch    ; st=old$1,haystack
  Exch $2 ; st=old$1,old$2, $2=haystack
  Push $3
  Push $4
  Push $5
  StrLen $3 $1
  StrCpy $4 0
  ; $1=needle
  ; $2=haystack
  ; $3=len(needle)
  ; $4=cnt
  ; $5=tmp
  loop:
    StrCpy $5 $2 $3 $4
    StrCmp $5 $1 done
    StrCmp $5 "" done
    IntOp $4 $4 + 1
    Goto loop
  done:
  StrCpy $1 $2 "" $4
  Pop $5
  Pop $4
  Pop $3
  Pop $2
  Exch $1
FunctionEnd


System version checking:
;------------------------------------------------------------------------------
; GetWindowsVersion
;
; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/
; Returns on top of stack
;
; Windows Version (95, 98, ME, NT x.x, 2000)
; or
; '' (Unknown Windows Version)
;
; Usage:
;   Call GetWindowsVersion
;   Pop $0
;   ; at this point $0 is "NT 4.0" or whatnot

Function GetWindowsVersion
  Push $0
  Push $9
  ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
  StrCmp $0 "" 0 lbl_winnt
  ; we are not NT.
  ReadRegStr $0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion VersionNumber
 
  StrCpy $9 $0 1
  StrCmp $9 '4' 0 lbl_error

  StrCpy $9 $0 3

  StrCmp $9 '4.0' lbl_win32_95
  StrCmp $9 '4.9' lbl_win32_ME lbl_win32_98

  lbl_win32_95:
    StrCpy $0 '95'
  Goto lbl_done

  lbl_win32_98:
    StrCpy $0 '98'
  Goto lbl_done

  lbl_win32_ME:
    StrCpy $0 'ME'
  Goto lbl_done

  lbl_winnt: 

    StrCpy $9 $0 1
    StrCmp $9 '3' lbl_winnt_x
    StrCmp $9 '4' lbl_winnt_x
    StrCmp $9 '5' lbl_winnt_5 lbl_error

    lbl_winnt_x:
      StrCpy $0 "NT $0" 6
    Goto lbl_done

    lbl_winnt_5:
      Strcpy $0 '2000'
    Goto lbl_done

  lbl_error:
    Strcpy $0 ''
  lbl_done:
  Pop $9
  Exch $0
FunctionEnd

;------------------------------------------------------------------------------
; GetIEVersion
;
; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/
; Returns on top of stack
; 1-6 (Installed IE Version)
; or 
; '' (IE is not installed)
;
; Usage:
;   Call GetIEVersion
;   Pop $0
;   ; at this point $0 is "5" or whatnot

Function GetIEVersion
  Push $0
  ClearErrors
  ReadRegStr $0 HKLM "Software\Microsoft\Internet Explorer" "Version"
  IfErrors lbl_123 lbl_456

  lbl_456: ; ie 4+
    Strcpy $0 $0 1
  Goto lbl_done

  lbl_123: ; older ie version
    ClearErrors
    ReadRegStr $0 HKLM "Software\Microsoft\Internet Explorer" "IVer"
    IfErrors lbl_error

      StrCpy $0 $0 3
      StrCmp $0 '100' lbl_ie1
      StrCmp $0 '101' lbl_ie2
      StrCmp $0 '102' lbl_ie2

      StrCpy $0 '3' ; default to ie3 if not 100, 101, or 102.
      Goto lbl_done
        lbl_ie1: 
          StrCpy $0 '1'
        Goto lbl_done
        lbl_ie2:
          StrCpy $0 '2'
        Goto lbl_done
    lbl_error:
      StrCpy $0 ''
  lbl_done:
  Exch $0
FunctionEnd


;------------------------------------------------------------------------------
; IsFlashInstalled
;
; By Yazno, http://yazno.tripod.com/powerpimpit/
; Returns on top of stack
; 0 (Flash is not installed)
; or
; 1 (Flash is installed)
;
; Usage:
;   Call IsFlashInstalled
;   Pop $0
;   ; $0 at this point is "1" or "0"

Function IsFlashInstalled
 Push $0
 ClearErrors
 ReadRegStr $0 HKCR "CLSID\{D27CDB6E-AE6D-11cf-96B8-444553540000}" ""
 IfErrors lbl_na 
   StrCpy $0 1
 Goto lbl_end
 lbl_na:
   StrCpy $0 0
 lbl_end:
 Exch $0
FunctionEnd



Shared DLL functions:
;------------------------------------------------------------------------------
; un.RemoveSharedDLL
;
; Decrements a shared DLLs reference count, and removes if necessary.
; Use by passing one item on the stack (the full path of the DLL).
; Note: for use in the main installer (not the uninstaller), rename the
; function to RemoveSharedDLL.
; 
; Usage:
;   Push $SYSDIR\myDll.dll
;   Call un.RemoveShareDLL
;

Function un.RemoveSharedDLL
  Exch $9
  Push $0
  ReadRegDword $0 HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $9
  StrCmp $0 "" remove
    IntOp $0 $0 - 1
    IntCmp $0 0 rk rk uk
    rk:
      DeleteRegValue HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $9
    goto Remove
    uk:
      WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $9 $0
    Goto noremove
  remove:
    Delete /REBOOTOK $9
  noremove:
  Pop $0
  Pop $9
FunctionEnd


;------------------------------------------------------------------------------
; AddSharedDLL
;
; Increments a shared DLLs reference count.
; Use by passing one item on the stack (the full path of the DLL).
;
; Usage: 
;   Push $SYSDIR\myDll.dll
;   Call AddSharedDLL
;

Function AddSharedDLL
  Exch $9
  Push $0
  ReadRegDword $0 HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $9
  IntOp $0 $0 + 1
  WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $9 $0
  Pop $0
  Pop $9
FunctionEnd  


;------------------------------------------------------------------------------
; UpgradeDLL (macro)
;
; Updates a DLL (or executable) based on version resource information.
;
; Input: ${DLL_NAME} = input source file.
;        top of stack = full path on system to install file to.
;
; Output: none (removes full path from stack)
;
; Usage:
;
;  Push "$SYSDIR\atl.dll"
;  !define DLL_NAME atl.dll
;  !insertmacro UpgradeDLL
;

!macro UpgradeDLL
  Exch $0
  Push $1
  Push $2
  Push $3
  Push $4
  ClearErrors
  GetDLLVersionLocal ${DLL_NAME} $1 $2
  GetDLLVersion $0 $3 $4
  IfErrors upgrade_${DLL_NAME}
    IntCmpU $1 $3 noupgrade_${DLL_NAME} noupgrade_${DLL_NAME} upgrade_${DLL_NAME}
    IntCmpU $2 $4 noupgrade_${DLL_NAME} noupgrade_${DLL_NAME}
  upgrade_${DLL_NAME}:
    UnRegDLL $0
    File /oname=$0 ${DLL_NAME}
    RegDLL $0
  noupgrade_${DLL_NAME}:
  Pop $4
  Pop $3
  Pop $2
  Pop $1
  Pop $0
  !undef DLL_NAME
!macroend


Winamp functions:
;------------------------------------------------------------------------------
; GetWinampInstPath
; 
; takes no parameters
; returns with the winamp install directory on the stack (it will be
; an empty string if winamp is not detected).
;
; modifies no other variables
;
; Usage:
;   Call GetWinampInstPath
;   Pop $0
;   MessageBox MB_OK "Winamp installed at: $0"

Function GetWinampInstPath
  Push $0
  Push $1
  Push $2
  ReadRegStr $0 HKLM \
     "Software\Microsoft\Windows\CurrentVersion\Uninstall\Winamp" \ 
     "UninstallString"
  StrCmp $0 "" fin

    StrCpy $1 $0 1 0 ; get firstchar
    StrCmp $1 '"' "" getparent 
      ; if first char is ", let's remove "'s first.
      StrCpy $0 $0 "" 1
      StrCpy $1 0
      rqloop:
        StrCpy $2 $0 1 $1
        StrCmp $2 '"' rqdone
        StrCmp $2 "" rqdone
        IntOp $1 $1 + 1
        Goto rqloop
      rqdone:
      StrCpy $0 $0 $1
    getparent:
    ; the uninstall string goes to an EXE, let's get the directory.
    StrCpy $1 -1
    gploop:
      StrCpy $2 $0 1 $1
      StrCmp $2 "" gpexit
      StrCmp $2 "\" gpexit
      IntOp $1 $1 - 1
      Goto gploop
    gpexit:
    StrCpy $0 $0 $1

    StrCmp $0 "" fin
    IfFileExists $0\winamp.exe fin
      StrCpy $0 ""
  fin:
  Pop $2
  Pop $1
  Exch $0
FunctionEnd


;------------------------------------------------------------------------------
; GetWinampVisPath
; 
; requires $INSTDIR to point to the Winamp directory.
; sets $OUTDIR with vis plug-in path
;
; modifies no other variables

Function GetWinampVisPath 
  ReadINIStr $OUTDIR $INSTDIR\winamp.ini Winamp VisDir 
  StrCmp $OUTDIR "" NoINISetting
    IfFileExists $OUTDIR Good
  NoINISetting:
    StrCpy $OUTDIR $INSTDIR\Plugins
  Good:
FunctionEnd 


;------------------------------------------------------------------------------
; GetWinampDSPPath
; 
; requires $INSTDIR to point to the Winamp directory.
; sets $OUTDIR with dsp plug-in path
;
; modifies no other variables

Function GetWinampDSPPath 
  ReadINIStr $OUTDIR $INSTDIR\winamp.ini Winamp DSPDir 
  StrCmp $OUTDIR "" NoINISetting
    IfFileExists $OUTDIR Good
  NoINISetting:
    StrCpy $OUTDIR $INSTDIR\Plugins
  Good:
FunctionEnd 

;------------------------------------------------------------------------------
; GetWinampSkinPath
; 
; requires $INSTDIR to point to the Winamp directory.
; sets $OUTDIR with skin plug-in path
;
; modifies no other variables

Function GetWinampSkinPath 
  ReadINIStr $OUTDIR $INSTDIR\winamp.ini Winamp SkinDir 
  StrCmp $OUTDIR "" NoINISetting
    IfFileExists $OUTDIR Good
  NoINISetting:
    StrCpy $OUTDIR $INSTDIR\Skins
  Good:
FunctionEnd 

;------------------------------------------------------------------------------
; CloseWinamp
; 
; Closes all running instances of Winamp 1.x/2.x
;
; modifies no other variables
Function CloseWinamp
  Push $0
  loop:
    FindWindow $0 "Winamp v1.x"
    IntCmp $0 0 done
     SendMessage $0 16 0 0
     Sleep 100
     Goto loop
  done:
  Pop $0
FunctionEnd



Netscape functions:
;------------------------------------------------------------------------------
; InstallNetscapePlugin
;
; Replace 'mynetscapeplugin.dll' with the name of your DLL to extract.
;
; (pretty much untested, but should work)
;
; you may want to add is-netscape-running and error checking (if the file isn't writable)

Function InstallNetscapePlugin
  Push $OUTDIR
  Push $0
  Push $1
  StrCpy $0 0
  outer_loop:
    EnumRegKey $1 HKLM "Software\Netscape\Netscape Navigator" $0
    StrCmp $1 "" abort
    ReadRegStr $1 HKLM "Software\Netscape\Netscape Navigator\$1\Main" "Plugins Directory"    
    StrCmp $1 "" abort
    SetOutPath $1
    File mynetscapeplugin.dll
    IntOp $0 $0 + 1
  Goto outer_loop
  abort:
  Pop $1
  Pop $0
  Pop $OUTDIR
FunctionEnd

;------------------------------------------------------------------------------
; un.RemoveNetscapePlugin
;
; input: top of stack = dll name of plugin to remove
; output: none
; 
; Usage:
;   Push mynetscapepluging.dll
;   Call un.RemoveNetscapePlugin
;
; you may want to add is-netscape-running and error checking (if the delete doesn't work).


Function un.RemoveNetscapePlugin
  Exch $2
  Push $0
  Push $1
  StrCpy $0 0
  outer_loop:
    EnumRegKey $1 HKLM "Software\Netscape\Netscape Navigator" $0
    StrCmp $1 "" abort
    ReadRegStr $1 HKLM "Software\Netscape\Netscape Navigator\$1\Main" "Plugins Directory"    
    StrCmp $1 "" abort
    Delete /REBOOTOK $1\$2
    IntOp $0 $0 + 1
  Goto outer_loop
  abort:
  Pop $1
  Pop $0
  Pop $2
FunctionEnd