; OpenPencil Windows installer (NSIS). ; ; Why NSIS (not Inno Setup): the TS reference pipeline ; (apps/desktop/electron-builder.yml) also targets `nsis`, so installer UX ; stays consistent between the Electron and Rust shells. The release workflow ; installs NSIS explicitly before invoking makensis. ; ; Installs: ; openpencil-desktop.exe editor binary ; op.exe CLI binary (also shipped standalone as ; op-cli-.zip in the release; $INSTDIR is ; NOT added to PATH — doing so reliably needs the ; non-stock EnVar plugin, deferred) ; openpencil.ico icon used by shortcuts + the .op/.pen ProgID ; Uninstall.exe uninstaller (registered in Add/Remove Programs) ; ; File association: ProgID "OpenPencil.Document" under HKCR with DefaultIcon ; and an open command, claimed by .op and .pen. Writing the machine hive ; requires elevation, hence RequestExecutionLevel admin + $PROGRAMFILES64 — ; an intentional divergence from electron-builder's per-user install ; (perMachine: false): a per-user HKCU\Software\Classes claim silently loses ; to any pre-existing machine-level registration. `.fig` is deliberately not ; claimed on Windows (macOS-only association, parity with electron-builder's ; fileAssociations list which only covers .op). ; ; Compile (relative paths resolve against this script's directory, so the ; workflow passes absolute /D defines): ; makensis "/DVERSION=X.Y.Z" "/DARCH=x64" ^ ; "/DBIN_DIR=D:\w\target\x86_64-pc-windows-msvc\release" ^ ; "/DICON_FILE=D:\w\crates\op-host-desktop\assets\icon.ico" ^ ; "/DOUT_FILE=D:\w\OpenPencil-X.Y.Z-x64-win-setup.exe" ^ ; scripts\package-windows.nsi ; ; NOT compiled locally (no makensis on the macOS dev machine) — first real ; verification is the tag-push CI run. For ARCH=arm64 the installer stub is ; x86 and runs under emulation on Windows-on-ARM; the payload binaries are ; native aarch64. ; ; VIProductVersion is intentionally omitted: it requires a strict 4-part ; numeric version and would break compiles for pre-release tags like ; X.Y.Z-beta.1. Unicode true !include "MUI2.nsh" !ifndef VERSION !define VERSION "0.0.0" !endif !ifndef ARCH !define ARCH "x64" !endif !ifndef BIN_DIR !define BIN_DIR "..\target\release" !endif !ifndef ICON_FILE !define ICON_FILE "..\crates\op-host-desktop\assets\icon.ico" !endif !ifndef OUT_FILE !define OUT_FILE "OpenPencil-${VERSION}-${ARCH}-win-setup.exe" !endif !define PRODUCT_NAME "OpenPencil" !define EXE_NAME "openpencil-desktop.exe" !define CLI_NAME "op.exe" !define PROG_ID "OpenPencil.Document" !define REG_APP_KEY "Software\${PRODUCT_NAME}" !define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" Name "${PRODUCT_NAME}" OutFile "${OUT_FILE}" InstallDir "$PROGRAMFILES64\${PRODUCT_NAME}" InstallDirRegKey HKLM "${REG_APP_KEY}" "InstallDir" RequestExecutionLevel admin SetCompressor /SOLID lzma !define MUI_ICON "${ICON_FILE}" !define MUI_UNICON "${ICON_FILE}" !define MUI_ABORTWARNING !insertmacro MUI_PAGE_WELCOME ; allowToChangeInstallationDirectory parity with electron-builder.yml !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_LANGUAGE "English" Section "OpenPencil" SecMain SectionIn RO SetOutPath "$INSTDIR" File "${BIN_DIR}\${EXE_NAME}" File "${BIN_DIR}\${CLI_NAME}" File "/oname=openpencil.ico" "${ICON_FILE}" ; ANGLE fallback DLLs (libEGL.dll + libGLESv2.dll, optionally ; d3dcompiler_47.dll). Installed next to the exe so glutin's EGL path ; loads them when the native WGL OpenGL context can't drive Skia — the ; machines that were flash-exiting on startup (no/old GPU driver, ; software-only OpenGL, VMs, RDP). See ; `SharedSkiaContext::new_desktop` for the fallback wiring. ; ; `/nonfatal`: the release/CI build must stage these DLLs into ; ${BIN_DIR} (matching the target arch) before running makensis. Until ; that step exists the installer still builds (just without the ; fallback), so packaging never hard-breaks on a missing DLL. File /nonfatal "${BIN_DIR}\libEGL.dll" File /nonfatal "${BIN_DIR}\libGLESv2.dll" File /nonfatal "${BIN_DIR}\d3dcompiler_47.dll" WriteUninstaller "$INSTDIR\Uninstall.exe" WriteRegStr HKLM "${REG_APP_KEY}" "InstallDir" "$INSTDIR" ; Shortcuts — createDesktopShortcut / createStartMenuShortcut parity. CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}" CreateShortcut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" \ "$INSTDIR\${EXE_NAME}" "" "$INSTDIR\openpencil.ico" CreateShortcut "$DESKTOP\${PRODUCT_NAME}.lnk" \ "$INSTDIR\${EXE_NAME}" "" "$INSTDIR\openpencil.ico" ; Add/Remove Programs entry. WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}" WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${VERSION}" WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\openpencil.ico" WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "OpenPencil contributors" WriteRegStr HKLM "${UNINST_KEY}" "URLInfoAbout" "https://github.com/ZSeven-W/openpencil" WriteRegStr HKLM "${UNINST_KEY}" "InstallLocation" "$INSTDIR" WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" '"$INSTDIR\Uninstall.exe"' WriteRegDWORD HKLM "${UNINST_KEY}" "NoModify" 1 WriteRegDWORD HKLM "${UNINST_KEY}" "NoRepair" 1 ; File association: one ProgID claimed by both OpenPencil extensions. WriteRegStr HKCR "${PROG_ID}" "" "OpenPencil Document" WriteRegStr HKCR "${PROG_ID}\DefaultIcon" "" "$INSTDIR\openpencil.ico" WriteRegStr HKCR "${PROG_ID}\shell" "" "open" WriteRegStr HKCR "${PROG_ID}\shell\open\command" "" '"$INSTDIR\${EXE_NAME}" "%1"' WriteRegStr HKCR ".op" "" "${PROG_ID}" WriteRegStr HKCR ".op" "Content Type" "application/x-openpencil" WriteRegStr HKCR ".pen" "" "${PROG_ID}" WriteRegStr HKCR ".pen" "Content Type" "application/x-openpencil" ; SHCNE_ASSOCCHANGED — tell the shell to refresh icon/association caches. System::Call 'shell32::SHChangeNotify(i 0x08000000, i 0, i 0, i 0)' SectionEnd Section "Uninstall" Delete "$INSTDIR\${EXE_NAME}" Delete "$INSTDIR\${CLI_NAME}" Delete "$INSTDIR\openpencil.ico" Delete "$INSTDIR\Uninstall.exe" RMDir "$INSTDIR" Delete "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" RMDir "$SMPROGRAMS\${PRODUCT_NAME}" Delete "$DESKTOP\${PRODUCT_NAME}.lnk" ; Only unclaim the extensions if they still point at our ProgID — never ; clobber an association another app took over after us. ReadRegStr $0 HKCR ".op" "" StrCmp $0 "${PROG_ID}" 0 +2 DeleteRegKey HKCR ".op" ReadRegStr $0 HKCR ".pen" "" StrCmp $0 "${PROG_ID}" 0 +2 DeleteRegKey HKCR ".pen" DeleteRegKey HKCR "${PROG_ID}" DeleteRegKey HKLM "${UNINST_KEY}" DeleteRegKey HKLM "${REG_APP_KEY}" System::Call 'shell32::SHChangeNotify(i 0x08000000, i 0, i 0, i 0)' SectionEnd