; BeyondProximity.iss - Inno Setup script for BeyondProximity driver installer ; ; Packages the BeyondProximity proximity-sensing driver into a single-click ; installer for tester distribution. Replicates all logic from ; scripts/deploy_driver.ps1 using Inno Setup declarative sections and ; Pascal Script. ; ; Invoked via CMake "package" target: ; cmake --build build --config Release --target package ; ; Or manually with ISCC.exe: ; ISCC.exe /DMyAppVersion=v0.1.0 /DDriverBuildDir=build\driver\BeyondProximity installer\BeyondProximity.iss ; --- Preprocessor defines --- #ifndef MyAppVersion #define MyAppVersion "v0.0.0-dev" #endif #ifndef DriverBuildDir #error "DriverBuildDir must be defined via /D on ISCC command line" #endif #ifndef DriverSourceDir #define DriverSourceDir DriverBuildDir #endif [Setup] AppName=BeyondProximity AppVersion={#MyAppVersion} AppPublisher=Bigscreen DefaultDirName={code:GetDefaultDirName} DisableWelcomePage=yes DisableDirPage=auto DisableReadyPage=yes DisableProgramGroupPage=yes DisableFinishedPage=no Uninstallable=no PrivilegesRequired=admin OutputDir=. OutputBaseFilename=BeyondProximity-Setup-{#MyAppVersion} SetupIconFile=compiler:SetupClassicIcon.ico [Dirs] Name: "{app}\bin\BeyondProximity\bin\win64" [Files] ; Nested driver DLL (from build output) Source: "{#DriverBuildDir}\bin\win64\driver_BeyondProximity.dll"; \ DestDir: "{app}\bin\BeyondProximity\bin\win64"; Flags: ignoreversion ; Nested driver manifest (from build output -- includes copied manifest) Source: "{#DriverBuildDir}\driver.vrdrivermanifest"; \ DestDir: "{app}\bin\BeyondProximity"; Flags: ignoreversion [InstallDelete] ; Clean up old flat-deploy artifacts from bin\win64\ root Type: files; Name: "{app}\bin\win64\driver_BeyondProximity.dll" Type: files; Name: "{app}\bin\win64\driver_bigscreenbeyond.dll" [Run] ; Register nested driver with SteamVR Filename: "{code:GetVrPathRegPath}"; \ Parameters: "adddriver ""{app}\bin\BeyondProximity"""; \ Flags: runhidden waituntilterminated; \ StatusMsg: "Registering driver with SteamVR..."; \ Check: VrPathRegExists ; Offer to launch SteamVR (checkbox on finished page) Filename: "steam://run/250820"; \ Description: "Launch SteamVR"; \ Flags: postinstall shellexec nowait unchecked skipifsilent [Code] // --------------------------------------------------------------------------- // GetSteamInstallPath - Detect Steam install location from Windows Registry. // Checks HKLM (64-bit view) first, then HKCU. Returns empty string if not found. // --------------------------------------------------------------------------- function GetSteamInstallPath: String; var SteamPath: String; begin Result := ''; // Try HKLM (most reliable -- set by Steam installer) if RegQueryStringValue(HKLM, 'SOFTWARE\WOW6432Node\Valve\Steam', 'InstallPath', SteamPath) then begin if SteamPath <> '' then begin Result := SteamPath; Log('Steam path from HKLM: ' + Result); Exit; end; end; // Try HKCU (user-level -- may use forward slashes) if RegQueryStringValue(HKCU, 'SOFTWARE\Valve\Steam', 'SteamPath', SteamPath) then begin if SteamPath <> '' then begin StringChangeEx(SteamPath, '/', '\', True); Result := SteamPath; Log('Steam path from HKCU: ' + Result); Exit; end; end; Log('Steam path not found in registry, using default'); end; // --------------------------------------------------------------------------- // GetDefaultDirName - Scripted constant for DefaultDirName. // Uses detected Steam path or falls back to {autopf}\Steam. // --------------------------------------------------------------------------- function GetDefaultDirName(Param: String): String; var SteamPath: String; begin SteamPath := GetSteamInstallPath; if SteamPath <> '' then Result := SteamPath + '\steamapps\common\Bigscreen Beyond Driver' else Result := ExpandConstant('{autopf}') + '\Steam\steamapps\common\Bigscreen Beyond Driver'; end; // --------------------------------------------------------------------------- // GetVrPathRegPath - Returns full path to vrpathreg.exe using detected Steam path. // --------------------------------------------------------------------------- function GetVrPathRegPath(Param: String): String; var SteamPath: String; begin SteamPath := GetSteamInstallPath; if SteamPath <> '' then Result := SteamPath + '\steamapps\common\SteamVR\bin\win64\vrpathreg.exe' else Result := ExpandConstant('{autopf}') + '\Steam\steamapps\common\SteamVR\bin\win64\vrpathreg.exe'; end; // --------------------------------------------------------------------------- // VrPathRegExists - Check function for [Run] section: does vrpathreg.exe exist? // --------------------------------------------------------------------------- function VrPathRegExists: Boolean; begin Result := FileExists(GetVrPathRegPath('')); end; // --------------------------------------------------------------------------- // IsProcessRunning - Check if a named process is running via WMI // Uses OLE automation to query Win32_Process. Falls through (returns False) // if WMI is unavailable, allowing the install to proceed. // --------------------------------------------------------------------------- function IsProcessRunning(const ProcessName: String): Boolean; var WbemLocator, WbemServices, WbemObjectSet: Variant; begin Result := False; try WbemLocator := CreateOleObject('WbemScripting.SWbemLocator'); WbemServices := WbemLocator.ConnectServer('', 'root\cimv2'); WbemObjectSet := WbemServices.ExecQuery( 'SELECT Name FROM Win32_Process WHERE Name="' + ProcessName + '"'); Result := (WbemObjectSet.Count > 0); except // WMI unavailable -- fall through, allow install Log('WMI query failed for process detection; allowing install to proceed'); end; end; // --------------------------------------------------------------------------- // PrepareToInstall - Block installation if SteamVR (vrserver.exe) is running. // SteamVR locks driver DLLs in memory; overwriting them while running can // cause silent failures or crashes. // --------------------------------------------------------------------------- function PrepareToInstall(var NeedsRestart: Boolean): String; begin Result := ''; if IsProcessRunning('vrserver.exe') then Result := 'SteamVR is currently running. Please close SteamVR before installing BeyondProximity.'; end; // --------------------------------------------------------------------------- // NextButtonClick - Validate the selected directory on the dir selection page. // Checks for driver.vrdrivermanifest and resources\ directory to confirm this // is a genuine Bigscreen Beyond Driver installation. // --------------------------------------------------------------------------- function NextButtonClick(CurPageID: Integer): Boolean; var Dir: String; begin Result := True; if CurPageID = wpSelectDir then begin Dir := WizardDirValue; if not FileExists(Dir + '\driver.vrdrivermanifest') then begin MsgBox('The selected folder does not appear to be a Bigscreen Beyond Driver installation.' + #13#10 + 'Expected to find driver.vrdrivermanifest.', mbError, MB_OK); Result := False; end else if not DirExists(Dir + '\resources') then begin MsgBox('The selected folder does not appear to be a Bigscreen Beyond Driver installation.' + #13#10 + 'Expected to find a resources\ directory.', mbError, MB_OK); Result := False; end; end; end; // --------------------------------------------------------------------------- // RestoreRootManifest - If the root driver.vrdrivermanifest was previously // modified to resourceOnly=false (by an older deploy), restore the original // content with resourceOnly=true so the root driver stays as resource-only. // --------------------------------------------------------------------------- procedure RestoreRootManifest; var ManifestPath: String; Content, OriginalManifest: AnsiString; begin ManifestPath := ExpandConstant('{app}\driver.vrdrivermanifest'); if FileExists(ManifestPath) then begin if LoadStringFromFile(ManifestPath, Content) then begin if Pos('"resourceOnly" : false', Content) > 0 then begin OriginalManifest := '{' + #13#10 + #9 + '"alwaysActivate": false,' + #13#10 + #9 + '"name" : "bigscreenbeyond",' + #13#10 + #9 + '"directory" : "",' + #13#10 + #9 + '"resourceOnly" : true,' + #13#10 + #9 + '"hmd_presence" : []' + #13#10 + '}'; SaveStringToFile(ManifestPath, OriginalManifest, False); Log('Restored root manifest to resourceOnly=true'); end; end; end; end; // --------------------------------------------------------------------------- // RestoreVrresources - If driver.vrresources was previously patched to use // {BeyondProximity} icon paths, restore them to {bigscreenbeyond}. // --------------------------------------------------------------------------- procedure RestoreVrresources; var VrresourcesPath: String; RawContent: AnsiString; Content: String; begin VrresourcesPath := ExpandConstant('{app}\resources\driver.vrresources'); if FileExists(VrresourcesPath) then begin if LoadStringFromFile(VrresourcesPath, RawContent) then begin Content := String(RawContent); if Pos('{BeyondProximity}', Content) > 0 then begin StringChangeEx(Content, '{BeyondProximity}', '{bigscreenbeyond}', True); SaveStringToFile(VrresourcesPath, AnsiString(Content), False); Log('Restored driver.vrresources icon paths to {bigscreenbeyond}'); end; end; end; end; // --------------------------------------------------------------------------- // CurStepChanged - Post-install hook to restore root manifest and vrresources // after files have been copied and old artifacts deleted. // --------------------------------------------------------------------------- procedure CurStepChanged(CurStep: TSetupStep); begin if CurStep = ssPostInstall then begin RestoreRootManifest; RestoreVrresources; end; end;