Files
ICCery/src-tauri/windows/hooks.nsh
T
gronod a8fd23afb5
Build Windows Packages / Build Windows (push) Successful in 7m26s
Build Linux Packages / Build Linux (push) Successful in 9m36s
fix(windows): apply dynamic shell folder drive mapping to uninstaller hooks
2026-08-29 10:41:57 +01:00

176 lines
4.9 KiB
NSIS

!include "LogicLib.nsh"
!include "FileFunc.nsh"
Var InstallArgyllUSB
Var MappedDrivesList
; Macro to check and map a drive if it is inaccessible/missing in the current session
!macro CheckAndMapMissingDrive DRIVE_PATH
Push $0
Push $1
Push $2
StrCpy $0 "${DRIVE_PATH}"
; Extract drive letter and colon (e.g. "Z:")
StrCpy $1 "$0" 1 0
StrCpy $0 "$1:"
; Verify if it is a valid drive letter A-Z
System::Call 'kernel32::GetDriveType(t "$0\\") i .r1'
${If} $1 <= 1
; Drive letter does not exist in this elevated session (e.g. domain user network home drive).
; Create temporary DOS device mapping to local $LOCALAPPDATA to prevent "Invalid Drive" error.
System::Call 'kernel32::DefineDosDevice(i 0, t "$0", t "$LOCALAPPDATA") i .r2'
${If} $2 != 0
StrCpy $MappedDrivesList "$MappedDrivesList$0|"
${EndIf}
${EndIf}
Pop $2
Pop $1
Pop $0
!macroend
!macro ScanAndMapShellFolderDrives
Push $0 ; loop index
Push $1 ; reg value name
Push $2 ; reg value data
Push $3 ; string length / extracted drive
Push $4 ; colon char
; 1. Scan HKCU User Shell Folders
StrCpy $0 0
loop_user_shell_folders:
EnumRegValue $1 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" $0
StrCmp $1 "" done_user_shell_folders
ReadRegStr $2 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" $1
IntOp $0 $0 + 1
StrLen $3 $2
${If} $3 >= 2
StrCpy $4 $2 1 1 ; 2nd character
${If} $4 == ":"
StrCpy $3 $2 2 0 ; "X:"
!insertmacro CheckAndMapMissingDrive $3
${EndIf}
${EndIf}
Goto loop_user_shell_folders
done_user_shell_folders:
; 2. Scan HKCU Shell Folders
StrCpy $0 0
loop_shell_folders:
EnumRegValue $1 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" $0
StrCmp $1 "" done_shell_folders
ReadRegStr $2 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" $1
IntOp $0 $0 + 1
StrLen $3 $2
${If} $3 >= 2
StrCpy $4 $2 1 1
${If} $4 == ":"
StrCpy $3 $2 2 0
!insertmacro CheckAndMapMissingDrive $3
${EndIf}
${EndIf}
Goto loop_shell_folders
done_shell_folders:
; 3. Scan $EXEDIR drive
${GetRoot} "$EXEDIR" $3
${If} $3 != ""
!insertmacro CheckAndMapMissingDrive $3
${EndIf}
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
!macroend
!macro CleanupTemporaryMappedDrives
Push $0
Push $1
Push $2
loop_cleanup_drives:
StrCmp $MappedDrivesList "" done_cleanup_drives
StrCpy $1 $MappedDrivesList 2 0 ; "X:"
StrCpy $MappedDrivesList $MappedDrivesList "" 3 ; strip "X:|"
System::Call 'kernel32::DefineDosDevice(i 2, t "$1", t "$LOCALAPPDATA") i .r2'
Goto loop_cleanup_drives
done_cleanup_drives:
Pop $2
Pop $1
Pop $0
!macroend
!macro NSIS_HOOK_PREINSTALL
StrCpy $InstallArgyllUSB 0
StrCpy $MappedDrivesList ""
; 1. Dynamically detect and map any missing shell folder drives referenced in HKCU
!insertmacro ScanAndMapShellFolderDrives
; 2. Ensure $INSTDIR is on a local fixed drive (not a network/remote drive or UNC path)
${GetRoot} "$INSTDIR" $0
System::Call 'kernel32::GetDriveType(t "$0") i .r1'
${If} $1 != 3
${OrIf} "$0" == "\\\\"
${OrIf} "$0" == "\\"
UserInfo::GetAccountType
Pop $0
${If} $0 == "Admin"
StrCpy $INSTDIR "$PROGRAMFILES64\ICCery"
${Else}
StrCpy $INSTDIR "$LOCALAPPDATA\Programs\ICCery"
${EndIf}
${EndIf}
; 3. Prompt for optional USB driver installation if running as Admin
UserInfo::GetAccountType
Pop $0
${If} $0 == "Admin"
SetShellVarContext all
MessageBox MB_YESNO|MB_ICONQUESTION \
"Install ArgyllCMS USB instrument drivers?$\r$\n$\r$\nRequired for spectrophotometers (i1Pro, ColorMunki, SpyderPrint, etc.)." \
IDNO skip_usb_prompt
StrCpy $InstallArgyllUSB 1
skip_usb_prompt:
${EndIf}
!macroend
!macro NSIS_HOOK_POSTINSTALL
; 1. Execute Argyll USB driver installer if opted in
${If} $InstallArgyllUSB == 1
IfFileExists "$INSTDIR\argyll\usb\ArgyllCMS_install_USB.exe" 0 check_resources
ExecWait '"$INSTDIR\argyll\usb\ArgyllCMS_install_USB.exe"'
Goto usb_done
check_resources:
IfFileExists "$INSTDIR\resources\argyll\usb\ArgyllCMS_install_USB.exe" 0 usb_missing
ExecWait '"$INSTDIR\resources\argyll\usb\ArgyllCMS_install_USB.exe"'
Goto usb_done
usb_missing:
MessageBox MB_ICONEXCLAMATION "ArgyllCMS USB driver installer was not found in the package."
usb_done:
${EndIf}
; 2. Clean up any temporary virtual DOS device mappings created during install
!insertmacro CleanupTemporaryMappedDrives
!macroend
!macro NSIS_HOOK_PREUNINSTALL
StrCpy $MappedDrivesList ""
!insertmacro ScanAndMapShellFolderDrives
!macroend
!macro NSIS_HOOK_POSTUNINSTALL
!insertmacro CleanupTemporaryMappedDrives
; Do not auto-run ArgyllCMS_uninstall_USB.exe. Driver removal is a
; separate admin action and can break other Argyll-based apps.
!macroend