# NSIS utility functions

### Contents:

- General utility
  - GetParent
  - TrimNewlines
  - GetParameters
  - StrStr
- System version checking
  - GetWindowsVersion
  - GetIEVersion
  - IsFlashInstalled
- Shared DLL functions
  - un.RemoveSharedDLL
  - AddSharedDLL
  - UpgradeDLL (macro)
- Winamp functions
  - GetWinampInstPath
  - GetWinampVisPath
  - GetWinampDSPPath
  - GetWinampSkinPath
  - CloseWinamp
- Netscape functions
  - InstallNetscapePlugin
  - un.RemoveNetscapePlugin

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