diff --git a/DnsServiceSetup/Windows/DnsServiceSetup.iss b/DnsServiceSetup/Windows/DnsServiceSetup.iss index 7710db54..8f523c8d 100644 --- a/DnsServiceSetup/Windows/DnsServiceSetup.iss +++ b/DnsServiceSetup/Windows/DnsServiceSetup.iss @@ -3,8 +3,9 @@ #define PRODUCT_VERSION "5.6" #define COMPANY "Technitium" #define TITLE "Technitium DNS Server" +#define APP_URL "https://technitium.com/dns/" -#define FILES_LOCATION "..\..\DnsService\bin\Release" +#define FILES_LOCATION "..\..\DnsService\bin\Release\net5.0-windows7.0" #define TRAYAPP_LOCATION "..\..\DnsServerSystemTrayApp\obj\Release" #define TRAYAPP_FILENAME "DnsServerSystemTrayApp.exe" @@ -12,18 +13,25 @@ #define SERVICE_FILE "DnsService.exe" #define SERVICE_DISPLAY_NAME "Technitium DNS Server" #define SERVICE_DESCRIPTION "Technitium DNS Server" -#define CONFIG_FOLDER "{app}\config" +#define CONFIG_FOLDER_COMPANY "{localappdata}\Technitium" +#define CONFIG_FOLDER_FULL CONFIG_FOLDER_COMPANY + "\DNS Server" + +#define LEGACY_INSTALLER_APPID "{9B86AC7F-53B3-4E31-B245-D4602D16F5C8}" +#define LEGACY_INSTALLER_CONFIG_PATH "{commonpf32}\Technitium\DNS Server\config" [Setup] PrivilegesRequired=admin AppName={#TITLE} AppVersion={#PRODUCT_VERSION} AppId={#APPID} -DefaultDirName={commonpf}\{#COMPANY}\{#PRODUCT_NAME} +DefaultDirName={commonpf32}\{#COMPANY}\{#PRODUCT_NAME} DefaultGroupName={#COMPANY} DisableProgramGroupPage=yes AppCopyright=Copyright (c) 2021 {#COMPANY} AppPublisher={#COMPANY} +AppSupportURL={#APP_URL} +AppPublisherURL={#APP_URL} + OutputDir=..\Release OutputBaseFilename=DnsServiceSetup CloseApplications=no @@ -33,7 +41,7 @@ WizardSmallImageFile=logo.bmp [Files] Source: "{#TRAYAPP_LOCATION}\{#TRAYAPP_FILENAME}"; DestDir: "{app}"; -Source: "{#FILES_LOCATION}\*.*"; Excludes: "*.pdb"; DestDir: "{app}"; Flags: recursesubdirs; +Source: "{#FILES_LOCATION}\*.*"; Excludes: "*.pdb,*.runtimeconfig.dev.json"; DestDir: "{app}"; Flags: recursesubdirs; [Tasks] Name: "desktopicon"; Description: "Create an icon on the &desktop"; @@ -45,16 +53,12 @@ ServiceInstallFailure=The DNS Service could not be installed. %1 ServiceManagerUnavailable=The Service Manager is not available! DependenciesDir=. -[Registry] -Root: HKLM; Subkey: "Software\{#COMPANY}"; Flags: uninsdeletekeyifempty -Root: HKCU; Subkey: "Software\{#COMPANY}"; Flags: uninsdeletekeyifempty - [Icons] Name: "{userprograms}\Technitium DNS Server"; Comment: "DNS Server Tray App"; Filename: "{app}\DnsServerSystemTrayApp.exe"; WorkingDir: "{app}\"; Flags: createonlyiffileexists Name: "{userdesktop}\Technitium DNS Server"; Filename: "{app}\DnsServerSystemTrayApp.exe"; WorkingDir: "{app}\"; Flags: createonlyiffileexists; Tasks: desktopicon [Run] -Filename: "{app}\DnsServerSystemTrayApp.exe"; Description: "Run the Tray App"; Flags: postinstall nowait +Filename: "{app}\DnsServerSystemTrayApp.exe"; Description: "Run the Tray App"; Flags: postinstall nowait; ;Include the dependency code #include "depend\lang\english.iss" diff --git a/DnsServiceSetup/Windows/DnsServiceSetup.pas b/DnsServiceSetup/Windows/DnsServiceSetup.pas index d04926d7..17e20381 100644 --- a/DnsServiceSetup/Windows/DnsServiceSetup.pas +++ b/DnsServiceSetup/Windows/DnsServiceSetup.pas @@ -12,6 +12,23 @@ begin RegQueryStringValue(HKCU, UninstallKey, 'UninstallString', Value)) and (Value <> ''); end; +function IsLegacyInstallerInstalled: Boolean; +var + Value: string; + UninstallKey: string; +begin + UninstallKey := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#LEGACY_INSTALLER_APPID}'; + Result := (RegQueryStringValue(HKLM, UninstallKey, 'UninstallString', Value) or + RegQueryStringValue(HKCU, UninstallKey, 'UninstallString', Value)) and (Value <> ''); +end; + +function IsLegacyConfigAvailable: Boolean; +var + Value: string; +begin + Result := DirExists(ExpandConstant('{#LEGACY_INSTALLER_CONFIG_PATH}')); +end; + //Skips the Task selection screen if an upgrade install function ShouldSkipPage(PageID: Integer): Boolean; begin @@ -22,6 +39,15 @@ function InitializeSetup(): boolean; begin //Specify the dependencies to install here dotnet_5_desktop(); + if IsLegacyInstallerInstalled or IsLegacyConfigAvailable then begin + AdditionalMemo := AdditionalMemo + #13#10 + #13#10 + 'Previous Version:'; + end; + if IsLegacyInstallerInstalled then begin + AdditionalMemo := AdditionalMemo + #13#10 + ' Remove Legacy Installer'; + end; + if IsLegacyConfigAvailable then begin + AdditionalMemo := AdditionalMemo + #13#10 + ' Migrate Configuration'; + end; Result := true; end; @@ -32,6 +58,14 @@ begin Exec(ExpandConstant('taskkill.exe'), '/f /im ' + '"' + fileName + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); end; +function MsiExecUnins(appId: String): Integer; +var + ResultCode: Integer; +begin + ShellExec('', 'msiexec.exe', '/x ' + appId + ' /qn', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + Result := ResultCode; +end; + procedure KillTrayApp; //Kill the tray app. Inno Setup cannot seem to close it through the "Close Applications" dialog. begin TaskKill('{#TRAYAPP_FILENAME}'); @@ -147,19 +181,109 @@ begin end; end; +procedure UninstallLegacyInstaller; +var + ResultCode: Integer; +begin + if IsLegacyInstallerInstalled then begin + Log('Uninstall MSI installer item'); + ResultCode := MsiExecUnins('{#LEGACY_INSTALLER_APPID}'); + Log('Result code ' + IntToStr(ResultCode)); + end; +end; + procedure RemoveConfiguration(); //Removes the configuration left by the DNS Server var DeleteSuccess: Boolean; begin Log('Delete configuration folder'); - DeleteSuccess := DelTree(ExpandConstant('{#CONFIG_FOLDER}'), True, True, True); + DeleteSuccess := DelTree(ExpandConstant('{#CONFIG_FOLDER_FULL}'), True, True, True); if not DeleteSuccess then begin - Log('Not all configuration files were deleted succesfully in ' + ExpandConstant('{#CONFIG_FOLDER}')); + Log('Not all configuration files were deleted succesfully in ' + ExpandConstant('{#CONFIG_FOLDER_FULL}')); SuppressibleMsgBox(ExpandConstant('{cm:RemoveConfigFail}'), mbError, MB_OK, IDOK); end; end; +procedure DirectoryCopy(SourcePath, DestPath: string); +var + FindRec: TFindRec; + SourceFilePath: string; + DestFilePath: string; +begin + if FindFirst(SourcePath + '\*', FindRec) then + begin + try + repeat + if (FindRec.Name <> '.') and (FindRec.Name <> '..') then + begin + SourceFilePath := SourcePath + '\' + FindRec.Name; + DestFilePath := DestPath + '\' + FindRec.Name; + if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then + begin + if FileCopy(SourceFilePath, DestFilePath, False) then + begin + Log(Format('Copied %s to %s', [SourceFilePath, DestFilePath])); + end + else + begin + Log(Format('Failed to copy %s to %s', [SourceFilePath, DestFilePath])); + end; + end + else + begin + if DirExists(DestFilePath) or CreateDir(DestFilePath) then + begin + Log(Format('Created %s', [DestFilePath])); + DirectoryCopy(SourceFilePath, DestFilePath); + end + else + begin + Log(Format('Failed to create %s', [DestFilePath])); + end; + end; + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end + else + begin + Log(Format('Failed to list %s', [SourcePath])); + end; +end; + +procedure MigrateConfiguration(); +var + ConfigDirExists : Boolean; +begin + + if IsLegacyConfigAvailable then begin + Log('Begin Configuration Migration'); + + ConfigDirExists := DirExists(ExpandConstant('{#CONFIG_FOLDER_COMPANY}')); + + if not ConfigDirExists then begin + Log('Create config folder company'); + CreateDir(ExpandConstant('{#CONFIG_FOLDER_COMPANY}')); + end; + + ConfigDirExists := DirExists(ExpandConstant('{#CONFIG_FOLDER_FULL}')); + + if not ConfigDirExists then begin + Log('Create config folder program'); + CreateDir(ExpandConstant('{#CONFIG_FOLDER_FULL}')); + end; + + DirectoryCopy(ExpandConstant('{#LEGACY_INSTALLER_CONFIG_PATH}'), ExpandConstant('{#CONFIG_FOLDER_FULL}')); + + DelTree(ExpandConstant('{#LEGACY_INSTALLER_CONFIG_PATH}'), true, true, true); + + Log('Complete Configuration Migration'); + end; +end; + procedure PromptRemoveConfiguration(); //Asks users if they want their config removed. On unattended installs, will keep config unless /removeconfig=true is supplied begin case ExpandConstant('{param:removeconfig|prompt}') of @@ -176,11 +300,26 @@ end; procedure CurStepChanged(CurStep: TSetupStep); begin if CurStep = ssInstall then begin //Step happens just before installing files + WizardForm.StatusLabel.Caption := 'Stopping Tray App...'; KillTrayApp(); //Stop the tray app if running - DoRemoveService(); //Stop and remove the service if installed + + if IsLegacyInstallerInstalled or IsLegacyConfigAvailable then begin + WizardForm.StatusLabel.Caption := 'Stopping Service...'; + DoStopService(); //Stop the service if running + + WizardForm.StatusLabel.Caption := 'Removing Legacy Installer...'; + UninstallLegacyInstaller(); //Uninstall Legacy Installer if Installed already + + WizardForm.StatusLabel.Caption := 'Migrating Configuration...'; + MigrateConfiguration(); //Shift configuration into correct path + end else begin + WizardForm.StatusLabel.Caption := 'Uninstalling Service...'; + DoRemoveService(); //Stop and remove the service if installed + end; end; if CurStep = ssPostInstall then begin //Step happens just after installing files - DoInstallService(); //Install service after all files installed + WizardForm.StatusLabel.Caption := 'Installing Service...'; + DoInstallService(); //Install service after all files installed, if not a portable install end; end; @@ -188,7 +327,9 @@ procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); begin if CurUninstallStep = usUninstall then //Step happens before processing uninstall log begin + UninstallProgressForm.StatusLabel.Caption := 'Stopping Tray App...'; KillTrayApp(); //Stop the tray app if running + UninstallProgressForm.StatusLabel.Caption := 'Uninstalling Service...'; DoRemoveService(); //Stop and remove the service end; if CurUninstallStep = usPostUninstall then //Step happens after processing uninstall log diff --git a/DnsServiceSetup/Windows/depend/products.pas b/DnsServiceSetup/Windows/depend/products.pas index 4d13bf9d..b040bfc9 100644 --- a/DnsServiceSetup/Windows/depend/products.pas +++ b/DnsServiceSetup/Windows/depend/products.pas @@ -18,6 +18,7 @@ var products: array of TProduct; delayedReboot, isForcedX86: boolean; DependencyPage: TOutputProgressWizardPage; + AdditionalMemo: string; procedure AddProduct(filename, parameters, title, size, url: string; forceSuccess, installClean, mustRebootAfter : boolean); { @@ -228,6 +229,8 @@ begin if MemoTasksInfo <> '' then s := s + MemoTasksInfo; + s := s + AdditionalMemo; + Result := s end;