Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions build/nsis-installer.nsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
;Inspired by:
; https://gist.github.com/bogdibota/062919938e1ed388b3db5ea31f52955c
; https://stackoverflow.com/questions/34177547/detect-if-visual-c-redistributable-for-visual-studio-2013-is-installed
; https://stackoverflow.com/a/54391388
; https://github.com/GitCommons/cpp-redist-nsis/blob/main/installer.nsh

;Find latests downloads here:
; https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist

!include LogicLib.nsh
!include x64.nsh

; https://github.com/electron-userland/electron-builder/issues/1122
!ifndef BUILD_UNINSTALLER
Function checkVCRedist
ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
FunctionEnd
Comment on lines +15 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

VC++ detection reads the wrong registry view and ignores ARM64; may false-negative on 64-bit/ARM64 systems

NSIS is a 32-bit process; without SetRegView 64 you’ll read the 32-bit WOW6432Node. Also, you always check the x64 runtime and never the ARM64 runtime, so ARM64 systems will be misdetected.

Apply this diff to query the correct 64-bit view and pick the runtime key by system arch:

-  Function checkVCRedist
-    ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
-  FunctionEnd
+  Function checkVCRedist
+    ; Return 1 if the required VC++ runtime is installed for the current system arch (x64/arm64), else 0
+    Push $R0
+    Push $R1
+    Push $R2
+    StrCpy $0 "0"
+    ; Always query the 64-bit registry view on 64-bit Windows
+    SetRegView 64
+    ReadEnvStr $R1 "PROCESSOR_ARCHITECTURE"
+    ReadEnvStr $R2 "PROCESSOR_ARCHITEW6432"
+    ${If} $R1 == "ARM64"
+    ${OrIf} $R2 == "ARM64"
+      ClearErrors
+      ReadRegDWORD $R0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\arm64" "Installed"
+    ${Else}
+      ClearErrors
+      ReadRegDWORD $R0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
+    ${EndIf}
+    ${If} ${Errors}
+      StrCpy $0 "0"
+    ${Else}
+      StrCpy $0 $R0
+    ${EndIf}
+    ; Restore default view for safety
+    SetRegView 32
+    Pop $R2
+    Pop $R1
+    Pop $R0
+  FunctionEnd
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Function checkVCRedist
ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
FunctionEnd
Function checkVCRedist
; Return 1 if the required VC++ runtime is installed for the current system arch (x64/arm64), else 0
Push $R0
Push $R1
Push $R2
StrCpy $0 "0"
; Always query the 64-bit registry view on 64-bit Windows
SetRegView 64
ReadEnvStr $R1 "PROCESSOR_ARCHITECTURE"
ReadEnvStr $R2 "PROCESSOR_ARCHITEW6432"
${If} $R1 == "ARM64"
${OrIf} $R2 == "ARM64"
ClearErrors
ReadRegDWORD $R0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\arm64" "Installed"
${Else}
ClearErrors
ReadRegDWORD $R0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
${EndIf}
${If} ${Errors}
StrCpy $0 "0"
${Else}
StrCpy $0 $R0
${EndIf}
; Restore default view for safety
SetRegView 32
Pop $R2
Pop $R1
Pop $R0
FunctionEnd
🤖 Prompt for AI Agents
In build/nsis-installer.nsh around lines 15 to 17, the current ReadRegDWORD runs
in the 32-bit registry view and always checks the x64 runtime key, causing false
negatives on 64-bit/ARM64 systems; call SetRegView 64 before reading the key
(and restore the previous view afterwards), detect the native system
architecture (e.g. check PROCESSOR_ARCHITECTURE or use your existing
RunningX64/RunningARM64 helper), choose the correct runtime registry subkey
("Runtimes\x64" for x64 or "Runtimes\arm64" for ARM64) and then ReadRegDWORD
"Installed" from that path so the installer correctly detects the VC++
redistributable on both x64 and ARM64 systems.


Function checkArchitectureCompatibility
; Initialize variables
StrCpy $0 "0" ; Default to incompatible
StrCpy $1 "" ; System architecture
StrCpy $3 "" ; App architecture

; Check system architecture using built-in NSIS functions
${If} ${RunningX64}
; Check if it's ARM64 by looking at processor architecture
ReadEnvStr $2 "PROCESSOR_ARCHITECTURE"
ReadEnvStr $4 "PROCESSOR_ARCHITEW6432"

${If} $2 == "ARM64"
${OrIf} $4 == "ARM64"
StrCpy $1 "arm64"
${Else}
StrCpy $1 "x64"
${EndIf}
${Else}
StrCpy $1 "x86"
${EndIf}

; Determine app architecture based on build variables
!ifdef APP_ARM64_NAME
!ifndef APP_64_NAME
StrCpy $3 "arm64" ; App is ARM64 only
!endif
!endif
!ifdef APP_64_NAME
!ifndef APP_ARM64_NAME
StrCpy $3 "x64" ; App is x64 only
!endif
!endif
!ifdef APP_64_NAME
!ifdef APP_ARM64_NAME
StrCpy $3 "universal" ; Both architectures available
!endif
!endif

; If no architecture variables are defined, assume x64
${If} $3 == ""
StrCpy $3 "x64"
${EndIf}

; Compare system and app architectures
${If} $3 == "universal"
; Universal build, compatible with all architectures
StrCpy $0 "1"
${ElseIf} $1 == $3
; Architectures match
StrCpy $0 "1"
${Else}
; Architectures don't match
StrCpy $0 "0"
${EndIf}
FunctionEnd
!endif

!macro customInit
Push $0
Push $1
Push $2
Push $3
Push $4

; Check architecture compatibility first
Call checkArchitectureCompatibility
${If} $0 != "1"
MessageBox MB_ICONEXCLAMATION "\
Architecture Mismatch$\r$\n$\r$\n\
This installer is not compatible with your system architecture.$\r$\n\
Your system: $1$\r$\n\
App architecture: $3$\r$\n$\r$\n\
Please download the correct version from:$\r$\n\
https://deepchat.thinkinai.xyz/"
ExecShell "open" "https://deepchat.thinkinai.xyz/"
Abort
${EndIf}

Call checkVCRedist
${If} $0 != "1"
MessageBox MB_YESNO "\
NOTE: ${PRODUCT_NAME} requires $\r$\n\
'Microsoft Visual C++ Redistributable'$\r$\n\
to function properly.$\r$\n$\r$\n\
Download and install now?" /SD IDYES IDYES InstallVCRedist IDNO DontInstall
InstallVCRedist:
inetc::get /CAPTION " " /BANNER "Downloading Microsoft Visual C++ Redistributable..." "https://aka.ms/vs/17/release/vc_redist.x64.exe" "$TEMP\vc_redist.x64.exe"
ExecWait "$TEMP\vc_redist.x64.exe /install /norestart"
;IfErrors InstallError ContinueInstall ; vc_redist exit code is unreliable :(
Call checkVCRedist
${If} $0 == "1"
Goto ContinueInstall
${EndIf}

;InstallError:
MessageBox MB_ICONSTOP "\
There was an unexpected error installing$\r$\n\
Microsoft Visual C++ Redistributable.$\r$\n\
The installation of ${PRODUCT_NAME} cannot continue."
DontInstall:
Abort
${EndIf}
Comment on lines +100 to +121
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Download and install the correct VC++ Redist for the running system (ARM64 vs x64) and clean up the temp file

Currently you always fetch vc_redist.x64.exe. On ARM64 systems (and ARM64 builds) this can install the wrong runtime and leave the app broken. Also, the downloaded file isn’t deleted.

Apply this diff to select the right URL and clean up:

-    InstallVCRedist:
-      inetc::get /CAPTION " " /BANNER "Downloading Microsoft Visual C++ Redistributable..." "https://aka.ms/vs/17/release/vc_redist.x64.exe" "$TEMP\vc_redist.x64.exe"
-      ExecWait "$TEMP\vc_redist.x64.exe /install /norestart"
+    InstallVCRedist:
+      ; Pick correct redist for the current system architecture
+      Push $5
+      Push $6
+      StrCpy $5 "x64"
+      StrCpy $6 "https://aka.ms/vs/17/release/vc_redist.x64.exe"
+      ${If} $1 == "arm64"
+        StrCpy $5 "arm64"
+        StrCpy $6 "https://aka.ms/vs/17/release/vc_redist.arm64.exe"
+      ${EndIf}
+      inetc::get /CAPTION " " /BANNER "Downloading Microsoft Visual C++ Redistributable..." "$6" "$TEMP\vc_redist.$5.exe"
+      ExecWait "$TEMP\vc_redist.$5.exe /install /norestart"
+      Delete "$TEMP\vc_redist.$5.exe"
+      Pop $6
+      Pop $5

Optional: If you prefer a fully silent redist install, add /quiet to the ExecWait command line.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
MessageBox MB_YESNO "\
NOTE: ${PRODUCT_NAME} requires $\r$\n\
'Microsoft Visual C++ Redistributable'$\r$\n\
to function properly.$\r$\n$\r$\n\
Download and install now?" /SD IDYES IDYES InstallVCRedist IDNO DontInstall
InstallVCRedist:
inetc::get /CAPTION " " /BANNER "Downloading Microsoft Visual C++ Redistributable..." "https://aka.ms/vs/17/release/vc_redist.x64.exe" "$TEMP\vc_redist.x64.exe"
ExecWait "$TEMP\vc_redist.x64.exe /install /norestart"
;IfErrors InstallError ContinueInstall ; vc_redist exit code is unreliable :(
Call checkVCRedist
${If} $0 == "1"
Goto ContinueInstall
${EndIf}
;InstallError:
MessageBox MB_ICONSTOP "\
There was an unexpected error installing$\r$\n\
Microsoft Visual C++ Redistributable.$\r$\n\
The installation of ${PRODUCT_NAME} cannot continue."
DontInstall:
Abort
${EndIf}
MessageBox MB_YESNO "\
NOTE: ${PRODUCT_NAME} requires $\r$\n\
'Microsoft Visual C++ Redistributable'$\r$\n\
to function properly.$\r$\n$\r$\n\
Download and install now?" /SD IDYES IDYES InstallVCRedist IDNO DontInstall
InstallVCRedist:
; Pick correct redist for the current system architecture
Push $5
Push $6
StrCpy $5 "x64"
StrCpy $6 "https://aka.ms/vs/17/release/vc_redist.x64.exe"
${If} $1 == "arm64"
StrCpy $5 "arm64"
StrCpy $6 "https://aka.ms/vs/17/release/vc_redist.arm64.exe"
${EndIf}
inetc::get /CAPTION " " /BANNER "Downloading Microsoft Visual C++ Redistributable..." "$6" "$TEMP\vc_redist.$5.exe"
ExecWait "$TEMP\vc_redist.$5.exe /install /norestart"
Delete "$TEMP\vc_redist.$5.exe"
Pop $6
Pop $5
;IfErrors InstallError ContinueInstall ; vc_redist exit code is unreliable :(
Call checkVCRedist
${If} $0 == "1"
Goto ContinueInstall
${EndIf}
;InstallError:
MessageBox MB_ICONSTOP "\
There was an unexpected error installing$\r$\n\
Microsoft Visual C++ Redistributable.$\r$\n\
The installation of ${PRODUCT_NAME} cannot continue."
DontInstall:
Abort
${EndIf}
🤖 Prompt for AI Agents
In build/nsis-installer.nsh around lines 100 to 121, the installer always
downloads vc_redist.x64.exe and never removes the temp file; update the script
to detect the OS architecture at runtime (ARM64 vs x64), choose the matching
Microsoft URL (use vc_redist.arm64.exe for ARM64, vc_redist.x64.exe otherwise),
download into "$TEMP\vc_redist.<arch>.exe", run ExecWait with your desired flags
(optionally add /quiet), then Call checkVCRedist and finally Delete the
downloaded temp file (e.g. Delete "$TEMP\vc_redist.<arch>.exe") in both success
and error paths so the temp file is cleaned up.

ContinueInstall:
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
!macroend
1 change: 1 addition & 0 deletions electron-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ nsis:
createDesktopShortcut: always
allowToChangeInstallationDirectory: true
oneClick: false
include: build/nsis-installer.nsh
afterSign: scripts/notarize.js
afterPack: scripts/afterPack.js
mac:
Expand Down
Loading