From 275b386c324d8384ab30ae5e6cf42e6dbe716975 Mon Sep 17 00:00:00 2001 From: 87owo <85057800+87owo@users.noreply.github.com> Date: Fri, 9 Oct 2026 12:29:57 +0800 Subject: [PATCH] Add files via upload --- PYAS_Inno.iss | 520 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 313 insertions(+), 207 deletions(-) diff --git a/PYAS_Inno.iss b/PYAS_Inno.iss index d1b87b0..b1a078d 100644 --- a/PYAS_Inno.iss +++ b/PYAS_Inno.iss @@ -1,6 +1,6 @@ #define AppId "{{a7d7bac3-93b8-4630-8308-c7a56bf7fdf4}" #define AppName "PYAS" -#define AppVersion "3.7.0.0" +#define AppVersion "3.7.1.0" #define AppPublisher "PYAS Security" #define AppURL "https://github.com/87owo/PYAS" #define AppExeName "PYAS.exe" @@ -38,6 +38,7 @@ SolidCompression=yes OutputDir=Output OutputBaseFilename=PYAS_Setup UsePreviousTasks=no +SetupLogging=yes [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" @@ -52,22 +53,22 @@ Name: "arabic"; MessagesFile: "SetupResources\Arabic.isl" Name: "russian"; MessagesFile: "SetupResources\Russian.isl" Name: "slovenian"; MessagesFile: "SetupResources\Slovenian.isl" -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}" +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}" [Files] Source: "Redist\VC_redist.x64.exe"; DestDir: "{tmp}\PYAS_Redist"; Flags: deleteafterinstall ignoreversion; AfterInstall: EnsureVCRedist -Source: "Redist\MicrosoftEdgeWebview2Setup.exe"; DestDir: "{tmp}\PYAS_Redist"; Flags: deleteafterinstall ignoreversion; AfterInstall: EnsureWebView2 +Source: "Redist\MicrosoftEdgeWebview2Setup.exe"; Flags: dontcopy noencryption Source: "Payload\Engine\*"; DestDir: "{app}\Engine"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "Payload\Interface\*"; DestDir: "{app}\Interface"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "Payload\License\*"; DestDir: "{app}\License"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "Payload\PYAS.exe"; DestDir: "{app}"; Flags: ignoreversion; AfterInstall: FinalizeDriverRemoval Source: "Payload\Plugins\*"; DestDir: "{app}\Plugins"; Flags: ignoreversion recursesubdirs createallsubdirs -[Registry] -Root: HKCU; Subkey: "Software\Classes\*\shell\PYAS_Scan"; Flags: uninsdeletekey dontcreatekey -Root: HKCU; Subkey: "Software\Classes\Directory\shell\PYAS_Scan"; Flags: uninsdeletekey dontcreatekey -Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueName: "PYAS_Security"; Flags: uninsdeletevalue dontcreatekey +[Registry] +Root: HKCU; Subkey: "Software\Classes\*\shell\PYAS_Scan"; Flags: uninsdeletekey dontcreatekey +Root: HKCU; Subkey: "Software\Classes\Directory\shell\PYAS_Scan"; Flags: uninsdeletekey dontcreatekey +Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueName: "PYAS_Security"; Flags: uninsdeletevalue dontcreatekey [UninstallDelete] Type: filesandordirs; Name: "{commonappdata}\PYAS" @@ -99,217 +100,322 @@ chinesetraditional.InstallVCRedist=安裝 Microsoft Visual C++ 執行庫 english.LegacyVersionDetected=An older version of PYAS was detected. Please uninstall it manually before installing. english.QuitFailed=PYAS or its driver could not be stopped safely. Restart Windows and run Setup again. english.DependencyInstallFailed=Required Microsoft runtime installation failed. Setup cannot continue. +english.WebView2InstallFailed=Microsoft Edge WebView2 Runtime could not be detected. Check your connection or install the Evergreen Runtime manually, then retry Setup.%n%nDetails: %1 +chinesesimplified.WebView2InstallFailed=无法检测到 Microsoft Edge WebView2 运行环境。请检查网络或手动安装 Evergreen 运行环境,然后重试安装。%n%n详细信息:%1 +chinesetraditional.WebView2InstallFailed=無法偵測到 Microsoft Edge WebView2 執行環境。請檢查網路或手動安裝 Evergreen 執行環境,再重試安裝。%n%n詳細資訊:%1 chinesesimplified.LegacyVersionDetected=检测到存在旧版 PYAS。请先手动卸载旧版后,再运行本安装程序。 chinesetraditional.LegacyVersionDetected=檢測到存在舊版 PYAS。請先手動卸載舊版後,再執行本安裝程式。 -[Code] -var - DependencyRestartRequired: Boolean; - DependenciesReady: Boolean; - -function FindWindow(lpClassName: LongWord; lpWindowName: string): HWND; - external 'FindWindowW@user32.dll stdcall'; - -function GetTickCount: Cardinal; - external 'GetTickCount@kernel32.dll stdcall'; - -function IsValidRuntimeVersion(Version: string): Boolean; -begin - Result := (Length(Trim(Version)) > 0) and (Trim(Version) <> '0.0.0.0'); -end; - -function IsWebView2Installed: Boolean; -var - Version: string; -begin - Result := False; - if RegQueryStringValue(HKLM, 'SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv', Version) then - Result := IsValidRuntimeVersion(Version); - if not Result and RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv', Version) then - Result := IsValidRuntimeVersion(Version); - if not Result and RegQueryStringValue(HKCU, 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv', Version) then - Result := IsValidRuntimeVersion(Version); -end; - -function IsVCRedistInstalled: Boolean; -var - Installed: Cardinal; - Version: string; -begin - Result := False; - if RegQueryDWordValue(HKLM64, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Installed', Installed) and (Installed = 1) then - begin - if RegQueryStringValue(HKLM64, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Version', Version) then - Result := IsValidRuntimeVersion(Version) - else - Result := True; - end; -end; - -function DependencyExitCodeSucceeded(ResultCode: Integer): Boolean; -begin - Result := (ResultCode = 0) or (ResultCode = 1641) or (ResultCode = 3010); - if (ResultCode = 1641) or (ResultCode = 3010) then - DependencyRestartRequired := True; -end; - -procedure EnsureVCRedist; -var - ResultCode: Integer; - InstallerPath: string; -begin - if IsVCRedistInstalled then Exit; - InstallerPath := ExpandConstant('{tmp}\PYAS_Redist\VC_redist.x64.exe'); - WizardForm.StatusLabel.Caption := CustomMessage('InstallingVCRuntime'); - if not Exec(InstallerPath, '/quiet /norestart', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) or - not DependencyExitCodeSucceeded(ResultCode) or not IsVCRedistInstalled then - begin - DependenciesReady := False; - RaiseException(CustomMessage('DependencyInstallFailed')); - end; -end; - -procedure EnsureWebView2; -var - ResultCode: Integer; - InstallerPath: string; -begin - if IsWebView2Installed then Exit; - InstallerPath := ExpandConstant('{tmp}\PYAS_Redist\MicrosoftEdgeWebview2Setup.exe'); - WizardForm.StatusLabel.Caption := CustomMessage('InstallingWebView2Runtime'); - if not Exec(InstallerPath, '/silent /install', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) or - not DependencyExitCodeSucceeded(ResultCode) or not IsWebView2Installed then - begin - DependenciesReady := False; - RaiseException(CustomMessage('DependencyInstallFailed')); - end; -end; - -function WaitForMainWindowToClose(TimeoutMs: Cardinal): Boolean; -var - Deadline: Cardinal; -begin - Deadline := GetTickCount + TimeoutMs; - repeat - if FindWindow(0, 'PYAS Security') = 0 then - begin - Result := True; - Exit; - end; - Sleep(100); - until GetTickCount >= Deadline; - Result := False; -end; - -function QuitOldInstance(InstallPath: string): Boolean; -var - ResultCode: Integer; - ExePath: string; -begin - Result := True; - ExePath := InstallPath + '\{#AppExeName}'; - if not FileExists(ExePath) then Exit; - - if not Exec(ExePath, '-quit', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then - begin - Result := False; - Exit; - end; - - Result := (ResultCode = 0) and WaitForMainWindowToClose(30000); -end; - -procedure FinalizeDriverRemoval; -var - ResultCode: Integer; - ExePath: string; -begin - ExePath := ExpandConstant('{app}\{#AppExeName}'); - if not Exec(ExePath, '-quit', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) or (ResultCode <> 0) then - RaiseException(CustomMessage('QuitFailed')); -end; - -function InitializeSetup(): Boolean; -var - OldInstallPath: string; - LegacyPath: string; -begin - DependencyRestartRequired := False; - DependenciesReady := True; - LegacyPath := ExpandConstant('{pf32}\{#AppName}'); - if DirExists(LegacyPath) and FileExists(LegacyPath + '\{#AppExeName}') then - begin - MsgBox(CustomMessage('LegacyVersionDetected'), mbCriticalError, MB_OK); - Result := False; - Exit; - end; - - if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' + ExpandConstant('{#AppId}') + '_is1', 'InstallLocation', OldInstallPath) or - RegQueryStringValue(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' + ExpandConstant('{#AppId}') + '_is1', 'InstallLocation', OldInstallPath) then - begin - if not QuitOldInstance(OldInstallPath) then - begin - MsgBox(CustomMessage('QuitFailed'), mbCriticalError, MB_OK); - Result := False; - Exit; - end; - end; - - Result := True; -end; - -function InitializeUninstall(): Boolean; -begin - Result := QuitOldInstance(ExpandConstant('{app}')); - if not Result then - MsgBox(CustomMessage('QuitFailed'), mbCriticalError, MB_OK); -end; - -function CanLaunchApp: Boolean; -begin - Result := DependenciesReady and not DependencyRestartRequired; -end; - -function NeedRestart: Boolean; -begin - Result := DependencyRestartRequired; -end; -procedure RemoveLegacyStartupTask; -var - TaskService: Variant; - RootFolder: Variant; -begin - try - TaskService := CreateOleObject('Schedule.Service'); - TaskService.Connect(); - RootFolder := TaskService.GetFolder('\'); - try - RootFolder.DeleteTask('PYAS_Security_ATS', 0); - Log('Removed legacy PYAS scheduled startup task'); - except - Log('Legacy PYAS scheduled startup task was not present or could not be removed'); - end; - except - Log('Task Scheduler COM was unavailable while cleaning the legacy startup task'); - end; -end; +[Code] +var + DependencyRestartRequired: Boolean; + DependenciesReady: Boolean; + +function FindWindow(lpClassName: LongWord; lpWindowName: string): HWND; + external 'FindWindowW@user32.dll stdcall'; + +function GetTickCount: Cardinal; + external 'GetTickCount@kernel32.dll stdcall'; + +function IsValidRuntimeVersion(Version: string): Boolean; +begin + Result := (Length(Trim(Version)) > 0) and (Trim(Version) <> '0.0.0.0'); +end; + +function QueryWebView2Version(RootKey: Integer; RootName: string; LogDetails: Boolean): Boolean; +var + Version: string; + PackedVersion: Int64; +begin + Result := False; + if RegQueryStringValue(RootKey, 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv', Version) then + begin + if StrToVersion(Trim(Version), PackedVersion) then + Result := PackedVersion > 0; + if LogDetails or Result then + Log('WebView2 ' + RootName + ': pv=' + Version + ', valid=' + IntToStr(Ord(Result))); + end + else if LogDetails then + Log('WebView2 ' + RootName + ': version not found or not readable'); +end; + +function IsWebView2Installed(LogDetails: Boolean): Boolean; +begin + Result := QueryWebView2Version(HKLM32, 'HKLM32', LogDetails); + if not Result and IsWin64 then + Result := QueryWebView2Version(HKLM64, 'HKLM64', LogDetails); + if not Result then + Result := QueryWebView2Version(HKCU32, 'HKCU32', LogDetails); + if not Result and IsWin64 then + Result := QueryWebView2Version(HKCU64, 'HKCU64', LogDetails); +end; + +function WaitForWebView2: Boolean; +var + Attempt: Integer; +begin + for Attempt := 0 to 60 do + begin + Result := IsWebView2Installed(False); + if Result then Exit; + if Attempt < 60 then Sleep(500); + end; + Result := False; +end; + +function IsVCRedistInstalled: Boolean; +var + Installed: Cardinal; + Version: string; +begin + Result := False; + if RegQueryDWordValue(HKLM64, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Installed', Installed) and (Installed = 1) then + begin + if RegQueryStringValue(HKLM64, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Version', Version) then + Result := IsValidRuntimeVersion(Version) + else + Result := True; + end; +end; + +function DependencyExitCodeSucceeded(ResultCode: Integer): Boolean; +begin + Result := (ResultCode = 0) or (ResultCode = 1641) or (ResultCode = 3010); + if (ResultCode = 1641) or (ResultCode = 3010) then + DependencyRestartRequired := True; +end; + +procedure EnsureVCRedist; +var + ResultCode: Integer; + InstallerPath: string; +begin + if IsVCRedistInstalled then Exit; + InstallerPath := ExpandConstant('{tmp}\PYAS_Redist\VC_redist.x64.exe'); + WizardForm.StatusLabel.Caption := CustomMessage('InstallingVCRuntime'); + if not Exec(InstallerPath, '/quiet /norestart', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) or + not DependencyExitCodeSucceeded(ResultCode) or not IsVCRedistInstalled then + begin + DependenciesReady := False; + RaiseException(CustomMessage('DependencyInstallFailed')); + end; +end; + +function EnsureWebView2: string; +var + ResultCode: Integer; + InstallerPath, Detail: string; + Started: Boolean; +begin + Result := ''; + if IsWebView2Installed(True) then + begin + Log('WebView2 is already installed; skipping the bootstrapper'); + Exit; + end; + WizardForm.PreparingLabel.Caption := CustomMessage('InstallingWebView2Runtime'); + ExtractTemporaryFile('MicrosoftEdgeWebview2Setup.exe'); + InstallerPath := ExpandConstant('{tmp}\MicrosoftEdgeWebview2Setup.exe'); + Log('Starting WebView2 bootstrapper: ' + InstallerPath + ' /silent /install'); + ResultCode := -1; + Started := Exec(InstallerPath, '/silent /install', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + if Started then + begin + Detail := Format('WebView2 installer exit code: %d (0x%x)', [ResultCode, ResultCode]); + if not DependencyExitCodeSucceeded(ResultCode) then + Log('WebView2 installer returned a non-success code; checking the runtime before failing'); + end + else + Detail := Format('WebView2 installer launch error: %d (%s)', [ResultCode, SysErrorMessage(ResultCode)]); + Log(Detail); + if IsWebView2Installed(True) then + begin + Log('WebView2 was detected after the installation attempt; continuing Setup'); + Exit; + end; + if Started then + begin + Log('Waiting up to 30 seconds for WebView2 registration'); + if WaitForWebView2 then + begin + Log('WebView2 registration completed; continuing Setup'); + Exit; + end; + end; + IsWebView2Installed(True); + Log('WebView2 prerequisite failed: ' + Detail); + Result := FmtMessage(CustomMessage('WebView2InstallFailed'), [Detail]); +end; + +function PrepareToInstall(var NeedsRestart: Boolean): string; +begin + DependenciesReady := False; + try + Result := EnsureWebView2; + except + Log('WebView2 prerequisite exception: ' + GetExceptionMessage); + Result := FmtMessage(CustomMessage('WebView2InstallFailed'), [GetExceptionMessage]); + end; + DependenciesReady := Result = ''; + NeedsRestart := DependencyRestartRequired; +end; + +function WaitForMainWindowToClose(TimeoutMs: Cardinal): Boolean; +var + Deadline: Cardinal; +begin + Deadline := GetTickCount + TimeoutMs; + repeat + if FindWindow(0, 'PYAS Security') = 0 then + begin + Result := True; + Exit; + end; + Sleep(100); + until GetTickCount >= Deadline; + Result := False; +end; + +function QuitOldInstance(InstallPath: string): Boolean; +var + ResultCode: Integer; + ExePath: string; +begin + Result := True; + ExePath := InstallPath + '\{#AppExeName}'; + if not FileExists(ExePath) then Exit; + + if not Exec(ExePath, '-quit', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then + begin + Result := False; + Exit; + end; + + Result := (ResultCode = 0) and WaitForMainWindowToClose(30000); +end; + +procedure FinalizeDriverRemoval; +var + ResultCode: Integer; + ExePath: string; +begin + ExePath := ExpandConstant('{app}\{#AppExeName}'); + if not Exec(ExePath, '-quit', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) or (ResultCode <> 0) then + RaiseException(CustomMessage('QuitFailed')); +end; + +function InitializeSetup(): Boolean; +var + OldInstallPath: string; + LegacyPath: string; +begin + DependencyRestartRequired := False; + DependenciesReady := True; + LegacyPath := ExpandConstant('{pf32}\{#AppName}'); + if DirExists(LegacyPath) and FileExists(LegacyPath + '\{#AppExeName}') then + begin + MsgBox(CustomMessage('LegacyVersionDetected'), mbCriticalError, MB_OK); + Result := False; + Exit; + end; + + if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' + ExpandConstant('{#AppId}') + '_is1', 'InstallLocation', OldInstallPath) or + RegQueryStringValue(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' + ExpandConstant('{#AppId}') + '_is1', 'InstallLocation', OldInstallPath) then + begin + if not QuitOldInstance(OldInstallPath) then + begin + MsgBox(CustomMessage('QuitFailed'), mbCriticalError, MB_OK); + Result := False; + Exit; + end; + end; + + Result := True; +end; + +function InitializeUninstall(): Boolean; +begin + Result := QuitOldInstance(ExpandConstant('{app}')); + if not Result then + MsgBox(CustomMessage('QuitFailed'), mbCriticalError, MB_OK); +end; + +function CanLaunchApp: Boolean; +begin + Result := DependenciesReady and not DependencyRestartRequired; +end; + +function NeedRestart: Boolean; +begin + Result := DependencyRestartRequired; +end; +procedure RemoveLegacyStartupTask; +var + TaskService: Variant; + RootFolder: Variant; +begin + try + TaskService := CreateOleObject('Schedule.Service'); + TaskService.Connect(); + RootFolder := TaskService.GetFolder('\'); + try + RootFolder.DeleteTask('PYAS_Security_ATS', 0); + Log('Removed legacy PYAS scheduled startup task'); + except + Log('Legacy PYAS scheduled startup task was not present or could not be removed'); + end; + except + Log('Task Scheduler COM was unavailable while cleaning the legacy startup task'); + end; +end; procedure CurStepChanged(CurStep: TSetupStep); begin - if CurStep = ssPostInstall then - begin - RemoveLegacyStartupTask; - end; + if CurStep = ssPostInstall then + begin + RemoveLegacyStartupTask; + end; +end; + +procedure RemoveStartupTasks; +var + TaskService, RootFolder, Tasks, Task: Variant; + I: Integer; + TaskName, ExecutablePath: string; +begin + try + TaskService := CreateOleObject('Schedule.Service'); + TaskService.Connect(); + RootFolder := TaskService.GetFolder('\'); + Tasks := RootFolder.GetTasks(1); + ExecutablePath := ExpandConstant('{app}\{#AppExeName}'); + for I := Tasks.Count downto 1 do + begin + Task := Tasks.Item(I); + TaskName := Task.Name; + if (TaskName = 'PYAS_Security_ATS') or (Pos('PYAS_Security_ATS_S-1-', TaskName) = 1) then + begin + if (Task.Definition.Actions.Count = 1) and + (CompareText(Task.Definition.Actions.Item(1).Path, ExecutablePath) = 0) then + begin + RootFolder.DeleteTask(TaskName, 0); + Log('Removed PYAS startup task: ' + TaskName); + end; + end; + end; + except + Log('Could not remove all PYAS startup tasks'); + end; end; procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); begin - if CurUninstallStep = usUninstall then - begin - RemoveLegacyStartupTask; + if CurUninstallStep = usUninstall then + begin + RemoveStartupTasks; end else if CurUninstallStep = usPostUninstall then begin DelTree(ExpandConstant('{app}'), True, True, True); end; -end; +end;