From 812d90440c85d3e036e5b10b278ebbd43a1a773a Mon Sep 17 00:00:00 2001 From: Maciej Zagozda Date: Fri, 27 Mar 2026 15:38:03 +0100 Subject: [PATCH 1/6] Initial version --- .github/workflows/build-installer.yml | 26 +- Installer/setup.exe | Bin 262144 -> 0 bytes Installer/setup.inf | 80 - Installer/setup.iss | 173 ++ Installer/x64 | 1 - README.md | 35 +- src/setup/doinst.c | 3010 ---------------------- src/setup/infinst.c | 760 ------ src/setup/infinst.h | 206 -- src/setup/instwiz.c | 1950 -------------- src/setup/language.h | 8 - src/setup/manifest.xml | 46 - src/setup/precomp.c | 4 - src/setup/precomp.h | 11 - src/setup/remove/ctxmenu.c | 132 - src/setup/remove/ctxmenu.h | 6 - src/setup/remove/icon1.ico | Bin 766 -> 0 bytes src/setup/remove/language.h | 8 - src/setup/remove/manifest.xml | 46 - src/setup/remove/precomp.c | 4 - src/setup/remove/precomp.h | 10 - src/setup/remove/process.c | 444 ---- src/setup/remove/process.h | 8 - src/setup/remove/remove.c | 1865 -------------- src/setup/remove/remove.rc | 223 -- src/setup/remove/remove.rc2 | 51 - src/setup/remove/remove_cz.rc2 | 10 - src/setup/remove/remove_de.rc2 | 10 - src/setup/remove/remove_en.rc2 | 10 - src/setup/remove/resource.h | 36 - src/setup/remove/utils.c | 95 - src/setup/remove/utils.h | 12 - src/setup/res/hand.cur | Bin 326 -> 0 bytes src/setup/res/icon.bmp | Bin 11076 -> 0 bytes src/setup/res/setup.ico | Bin 4710 -> 0 bytes src/setup/res/welcome.bmp | Bin 26992 -> 0 bytes src/setup/resource.h | 124 - src/setup/setup.rc | 1008 -------- src/vcxproj/salamand.sln | 28 - src/vcxproj/setup/remove.vcxproj | 127 - src/vcxproj/setup/remove.vcxproj.filters | 52 - src/vcxproj/setup/remove_base.props | 33 - src/vcxproj/setup/remove_debug.props | 23 - src/vcxproj/setup/remove_release.props | 28 - src/vcxproj/setup/setup.sln | 46 - src/vcxproj/setup/setup.vcxproj | 137 - src/vcxproj/setup/setup.vcxproj.filters | 97 - src/vcxproj/setup/setup_base.props | 33 - src/vcxproj/setup/setup_debug.props | 23 - src/vcxproj/setup/setup_release.props | 28 - src/vcxproj/setup/x64.props | 18 - src/vcxproj/setup/x86.props | 13 - tools/Create-Sfx.ps1 | 226 -- tools/prepare_installer.ps1 | 106 +- 54 files changed, 240 insertions(+), 11190 deletions(-) delete mode 100644 Installer/setup.exe delete mode 100644 Installer/setup.inf create mode 100644 Installer/setup.iss delete mode 100644 Installer/x64 delete mode 100644 src/setup/doinst.c delete mode 100644 src/setup/infinst.c delete mode 100644 src/setup/infinst.h delete mode 100644 src/setup/instwiz.c delete mode 100644 src/setup/language.h delete mode 100644 src/setup/manifest.xml delete mode 100644 src/setup/precomp.c delete mode 100644 src/setup/precomp.h delete mode 100644 src/setup/remove/ctxmenu.c delete mode 100644 src/setup/remove/ctxmenu.h delete mode 100644 src/setup/remove/icon1.ico delete mode 100644 src/setup/remove/language.h delete mode 100644 src/setup/remove/manifest.xml delete mode 100644 src/setup/remove/precomp.c delete mode 100644 src/setup/remove/precomp.h delete mode 100644 src/setup/remove/process.c delete mode 100644 src/setup/remove/process.h delete mode 100644 src/setup/remove/remove.c delete mode 100644 src/setup/remove/remove.rc delete mode 100644 src/setup/remove/remove.rc2 delete mode 100644 src/setup/remove/remove_cz.rc2 delete mode 100644 src/setup/remove/remove_de.rc2 delete mode 100644 src/setup/remove/remove_en.rc2 delete mode 100644 src/setup/remove/resource.h delete mode 100644 src/setup/remove/utils.c delete mode 100644 src/setup/remove/utils.h delete mode 100644 src/setup/res/hand.cur delete mode 100644 src/setup/res/icon.bmp delete mode 100644 src/setup/res/setup.ico delete mode 100644 src/setup/res/welcome.bmp delete mode 100644 src/setup/resource.h delete mode 100644 src/setup/setup.rc delete mode 100644 src/vcxproj/setup/remove.vcxproj delete mode 100644 src/vcxproj/setup/remove.vcxproj.filters delete mode 100644 src/vcxproj/setup/remove_base.props delete mode 100644 src/vcxproj/setup/remove_debug.props delete mode 100644 src/vcxproj/setup/remove_release.props delete mode 100644 src/vcxproj/setup/setup.sln delete mode 100644 src/vcxproj/setup/setup.vcxproj delete mode 100644 src/vcxproj/setup/setup.vcxproj.filters delete mode 100644 src/vcxproj/setup/setup_base.props delete mode 100644 src/vcxproj/setup/setup_debug.props delete mode 100644 src/vcxproj/setup/setup_release.props delete mode 100644 src/vcxproj/setup/x64.props delete mode 100644 src/vcxproj/setup/x86.props delete mode 100644 tools/Create-Sfx.ps1 diff --git a/.github/workflows/build-installer.yml b/.github/workflows/build-installer.yml index b473b731..e75d5621 100644 --- a/.github/workflows/build-installer.yml +++ b/.github/workflows/build-installer.yml @@ -16,7 +16,6 @@ jobs: env: BUILD_CONFIGURATION: Release SOLUTION_PATH: 'src\vcxproj\salamand.sln' - REMOVE_PROJ_PATH: 'src\vcxproj\setup\remove.vcxproj' # OPENSAL_BUILD_DIR MUST end with a backslash as expected by props files OPENSAL_BUILD_DIR: '${{ github.workspace }}\build_stage\' @@ -33,11 +32,6 @@ jobs: # We do NOT pass /p:OutDir here, we let the project props use OPENSAL_BUILD_DIR msbuild $env:SOLUTION_PATH /m /t:Build /p:Configuration=$env:BUILD_CONFIGURATION /p:Platform=x64 /p:PreferredToolArchitecture=x64 - - name: Build Uninstaller (Release | x64) - run: | - # remove.vcxproj also respects OPENSAL_BUILD_DIR - msbuild $env:REMOVE_PROJ_PATH /m /t:Build /p:Configuration=$env:BUILD_CONFIGURATION /p:Platform=x64 /p:PreferredToolArchitecture=x64 - - name: Download OpenSSL Libraries run: | $opensslZip = "openssl.zip" @@ -45,17 +39,29 @@ jobs: Expand-Archive -Path $opensslZip -DestinationPath "utils" -Force Remove-Item $opensslZip - - name: Prepare and Create Installer + - name: Install Inno Setup + run: | + choco install innosetup -y --no-progress + # Add Inno Setup to PATH + $innoPath = "C:\Program Files (x86)\Inno Setup 6" + echo "$innoPath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Prepare Installer Files + run: | + # Stage files for Inno Setup + powershell.exe -File tools\prepare_installer.ps1 -BuildDir $env:OPENSAL_BUILD_DIR -StagingDir "Installer_Staging" -BuildNumber ${{ github.run_number }} + + - name: Build Installer with Inno Setup run: | - # Our script is already robust and searches for files within OPENSAL_BUILD_DIR - powershell.exe -File tools\prepare_installer.ps1 -BuildDir $env:OPENSAL_BUILD_DIR -OutputPath "OpenSalamander_5.0.${{ github.run_number }}.exe" + # Compile the Inno Setup script + iscc.exe /DSourcePath="Installer_Staging" /DBuildNumber=${{ github.run_number }} "Installer\setup.iss" - name: Create Release uses: softprops/action-gh-release@v2 with: tag_name: 5.0.${{ github.run_number }} name: Open Salamander 5.0.${{ github.run_number }} - files: OpenSalamander_5.0.${{ github.run_number }}.exe + files: Installer\Output\OpenSalamander_5.0.${{ github.run_number }}.exe draft: false prerelease: false env: diff --git a/Installer/setup.exe b/Installer/setup.exe deleted file mode 100644 index 6d66f68f5436a03ffa630da8e1bda13dff5c3c39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262144 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 UYZtV2xv(-Dma{R34nu+e4{y6H8~^|S diff --git a/Installer/setup.inf b/Installer/setup.inf deleted file mode 100644 index bf1da214..00000000 --- a/Installer/setup.inf +++ /dev/null @@ -1,80 +0,0 @@ -[Private] -ApplicationName=Open Salamander 5.0 -ApplicationNameVer=Open Salamander 5.0 -DefaultDirectory=C:\ Program Files\Open Salamander 5.0 -LicenseFile=LICENSE -SkipChooseDirectory=0 - -[CopyFiles] -salamand.exe,%1\salamand.exe,0 -salmon.exe,%1\salmon.exe,0 -lang\english.slg,%1\lang\english.slg,0 -toolbars\Back.svg,%1\toolbars\Back.svg,0 -toolbars\CalculateDirectorySizes.svg,%1\toolbars\CalculateDirectorySizes.svg,0 -toolbars\CalculateOccupiedSpace.svg,%1\toolbars\CalculateOccupiedSpace.svg,0 -toolbars\ChangeAttributes.svg,%1\toolbars\ChangeAttributes.svg,0 -toolbars\ChangeCase.svg,%1\toolbars\ChangeCase.svg,0 -toolbars\ChangeDirectory.svg,%1\toolbars\ChangeDirectory.svg,0 -toolbars\ClipboardCopy.svg,%1\toolbars\ClipboardCopy.svg,0 -toolbars\ClipboardCut.svg,%1\toolbars\ClipboardCut.svg,0 -toolbars\ClipboardPaste.svg,%1\toolbars\ClipboardPaste.svg,0 -toolbars\CommandShell.svg,%1\toolbars\CommandShell.svg,0 -toolbars\CompareDirectories.svg,%1\toolbars\CompareDirectories.svg,0 -toolbars\Configuration.svg,%1\toolbars\Configuration.svg,0 -toolbars\ConnectNetworkDrive.svg,%1\toolbars\ConnectNetworkDrive.svg,0 -toolbars\Convert.svg,%1\toolbars\Convert.svg,0 -toolbars\Copy.svg,%1\toolbars\Copy.svg,0 -toolbars\CreateDirectory.svg,%1\toolbars\CreateDirectory.svg,0 -toolbars\Delete.svg,%1\toolbars\Delete.svg,0 -toolbars\Disconnect.svg,%1\toolbars\Disconnect.svg,0 -toolbars\DriveInformation.svg,%1\toolbars\DriveInformation.svg,0 -toolbars\Edit.svg,%1\toolbars\Edit.svg,0 -toolbars\EditNewFile.svg,%1\toolbars\EditNewFile.svg,0 -toolbars\Email.svg,%1\toolbars\Email.svg,0 -toolbars\Filter.svg,%1\toolbars\Filter.svg,0 -toolbars\FindFilesAndDirectories.svg,%1\toolbars\FindFilesAndDirectories.svg,0 -toolbars\FocusNameInOtherPanel.svg,%1\toolbars\FocusNameInOtherPanel.svg,0 -toolbars\Forward.svg,%1\toolbars\Forward.svg,0 -toolbars\GoToHotPath.svg,%1\toolbars\GoToHotPath.svg,0 -toolbars\GoToPathfromOtherPanel.svg,%1\toolbars\GoToPathfromOtherPanel.svg,0 -toolbars\GoToShortcutTarget.svg,%1\toolbars\GoToShortcutTarget.svg,0 -toolbars\HelpContents.svg,%1\toolbars\HelpContents.svg,0 -toolbars\HideSelectedNames.svg,%1\toolbars\HideSelectedNames.svg,0 -toolbars\HideUnselectedNames.svg,%1\toolbars\HideUnselectedNames.svg,0 -toolbars\Modify.svg,%1\toolbars\Modify.svg,0 -toolbars\Move.svg,%1\toolbars\Move.svg,0 -toolbars\MoveItemDown.svg,%1\toolbars\MoveItemDown.svg,0 -toolbars\MoveItemUp.svg,%1\toolbars\MoveItemUp.svg,0 -toolbars\New.svg,%1\toolbars\New.svg,0 -toolbars\NTFSCompress.svg,%1\toolbars\NTFSCompress.svg,0 -toolbars\NTFSUncompress.svg,%1\toolbars\NTFSUncompress.svg,0 -toolbars\OpenFolder.svg,%1\toolbars\OpenFolder.svg,0 -toolbars\OpenNameinOtherPanel.svg,%1\toolbars\OpenNameinOtherPanel.svg,0 -toolbars\Pack.svg,%1\toolbars\Pack.svg,0 -toolbars\ParentDirectory.svg,%1\toolbars\ParentDirectory.svg,0 -toolbars\PasteShortcut.svg,%1\toolbars\PasteShortcut.svg,0 -toolbars\Properties.svg,%1\toolbars\Properties.svg,0 -toolbars\QuickRename.svg,%1\toolbars\QuickRename.svg,0 -toolbars\Refresh.svg,%1\toolbars\Refresh.svg,0 -toolbars\RootDirectory.svg,%1\toolbars\RootDirectory.svg,0 -toolbars\Security.svg,%1\toolbars\Security.svg,0 -toolbars\SelectAll.svg,%1\toolbars\SelectAll.svg,0 -toolbars\SharedDirectories.svg,%1\toolbars\SharedDirectories.svg,0 -toolbars\ShowHiddenNames.svg,%1\toolbars\ShowHiddenNames.svg,0 -toolbars\SmartColumnMode.svg,%1\toolbars\SmartColumnMode.svg,0 -toolbars\SortByAttributes.svg,%1\toolbars\SortByAttributes.svg,0 -toolbars\SortByDate.svg,%1\toolbars\SortByDate.svg,0 -toolbars\SortByExtension.svg,%1\toolbars\SortByExtension.svg,0 -toolbars\SortByName.svg,%1\toolbars\SortByName.svg,0 -toolbars\SortBySize.svg,%1\toolbars\SortBySize.svg,0 -toolbars\SwapPanels.svg,%1\toolbars\SwapPanels.svg,0 -toolbars\Unpack.svg,%1\toolbars\Unpack.svg,0 -toolbars\UnselectAll.svg,%1\toolbars\UnselectAll.svg,0 -toolbars\UserMenu.svg,%1\toolbars\UserMenu.svg,0 -toolbars\View.svg,%1\toolbars\View.svg,0 -toolbars\Views.svg,%1\toolbars\Views.svg,0 -toolbars\WhatIsThis.svg,%1\toolbars\WhatIsThis.svg,0 - -[CreateShortcuts] -0,Open Salamander 5.0,%1\salamand.exe, -1,Open Salamander 5.0,%1\salamand.exe, \ No newline at end of file diff --git a/Installer/setup.iss b/Installer/setup.iss new file mode 100644 index 00000000..294d9bfb --- /dev/null +++ b/Installer/setup.iss @@ -0,0 +1,173 @@ +; Open Salamander Inno Setup Script +; This installer maintains all features from the previous custom installer + +#define MyAppName "Open Salamander" +#define MyAppVersion "5.0" +#define MyAppPublisher "Taskscape Ltd" +#define MyAppURL "https://www.opensalamander.com/" +#define MyAppExeName "salamand.exe" + +; Build number will be passed from command line during CI build +#ifndef BuildNumber + #define BuildNumber "0" +#endif + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +AppId={{F4A1E7D3-8E5C-4B2A-9F6E-3D7C8A5B9E2F} +AppName={#MyAppName} +AppVersion={#MyAppVersion}.{#BuildNumber} +AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +DefaultDirName={autopf}\{#MyAppName} +DefaultGroupName={#MyAppName} +AllowNoIcons=yes +LicenseFile=LICENSE +; SetupIconFile=..\src\setup\res\setup.ico +OutputBaseFilename=OpenSalamander_{#MyAppVersion}.{#BuildNumber} +Compression=lzma2/ultra64 +SolidCompression=yes +WizardStyle=modern +; 64-bit only installer +ArchitecturesAllowed=x64compatible +ArchitecturesInstallIn64BitMode=x64compatible +; Minimum Windows version +MinVersion=10.0.17763 +; Uninstaller settings +UninstallDisplayIcon={app}\{#MyAppExeName} +UninstallDisplayName={#MyAppName} {#MyAppVersion} + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[CustomMessages] +english.LaunchAfterInstall=Launch {#MyAppName} after installation + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked +Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 6.1; Check: not IsAdminInstallMode + +[Files] +; Main executables +Source: "{#SourcePath}\salamand.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "{#SourcePath}\salmon.exe"; DestDir: "{app}"; Flags: ignoreversion + +; Shell extensions +Source: "{#SourcePath}\salextx64.dll"; DestDir: "{app}"; Flags: ignoreversion regserver 64bit +Source: "{#SourcePath}\salextx86.dll"; DestDir: "{app}"; Flags: ignoreversion regserver 32bit + +; Utility executables (optional - only if present) +Source: "{#SourcePath}\salopen.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist +Source: "{#SourcePath}\salspawn.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist +Source: "{#SourcePath}\tserver.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist +Source: "{#SourcePath}\sfx7zip.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist +Source: "{#SourcePath}\zip2sfx.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist +Source: "{#SourcePath}\translator.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist +Source: "{#SourcePath}\salpvenv.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist +Source: "{#SourcePath}\fcremote.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist +Source: "{#SourcePath}\7zwrapper.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist + +; OpenSSL libraries for FTP encryption support +Source: "{#SourcePath}\utils\libeay32.dll"; DestDir: "{app}\utils"; Flags: ignoreversion skipifsourcedoesntexist +Source: "{#SourcePath}\utils\ssleay32.dll"; DestDir: "{app}\utils"; Flags: ignoreversion skipifsourcedoesntexist + +; License file +Source: "{#SourcePath}\LICENSE"; DestDir: "{app}"; Flags: ignoreversion + +; Language files for main application +Source: "{#SourcePath}\lang\*.slg"; DestDir: "{app}\lang"; Flags: ignoreversion + +; Toolbar icons +Source: "{#SourcePath}\toolbars\*.svg"; DestDir: "{app}\toolbars"; Flags: ignoreversion + +; Convert tables (character encoding tables) +Source: "{#SourcePath}\convert\centeuro\*"; DestDir: "{app}\convert\centeuro"; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist +Source: "{#SourcePath}\convert\cyrillic\*"; DestDir: "{app}\convert\cyrillic"; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist +Source: "{#SourcePath}\convert\westeuro\*"; DestDir: "{app}\convert\westeuro"; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist + +; Plugins - each plugin in its own directory with optional language files +Source: "{#SourcePath}\plugins\*"; DestDir: "{app}\plugins"; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist + +[Icons] +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon +Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchAfterInstall}"; Flags: nowait postinstall skipifsilent + +[Registry] +; Add application to App Paths for easier command-line launching +Root: HKLM; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\salamand.exe"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey +Root: HKLM; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\salamand.exe"; ValueType: string; ValueName: "Path"; ValueData: "{app}" + +[UninstallDelete] +; Clean up any files created during runtime +Type: filesandordirs; Name: "{app}\Temporary" +Type: dirifempty; Name: "{app}\plugins" +Type: dirifempty; Name: "{app}\lang" +Type: dirifempty; Name: "{app}\toolbars" +Type: dirifempty; Name: "{app}\convert" +Type: dirifempty; Name: "{app}\utils" +Type: dirifempty; Name: "{app}" + +[Code] +// Check if Open Salamander is currently running and offer to close it +function InitializeSetup(): Boolean; +var + ResultCode: Integer; +begin + Result := True; + + // Check if salamand.exe is running + if CheckForMutexes('OpenSalamanderMutex') then + begin + if MsgBox('Open Salamander is currently running. Please close it before continuing installation.' + #13#10 + #13#10 + + 'Click OK to retry or Cancel to exit setup.', mbError, MB_OKCANCEL) = IDCANCEL then + begin + Result := False; + end + else + begin + // Retry the check + Result := InitializeSetup(); + end; + end; +end; + +// Check if uninstalling while application is running +function InitializeUninstall(): Boolean; +begin + Result := True; + + if CheckForMutexes('OpenSalamanderMutex') then + begin + MsgBox('Open Salamander is currently running. Please close it before uninstalling.', mbError, MB_OK); + Result := False; + end; +end; + +// Cleanup old installation if upgrading from custom installer +procedure CurStepChanged(CurStep: TSetupStep); +var + OldUninstallString: String; + ResultCode: Integer; +begin + if CurStep = ssInstall then + begin + // Check for old custom uninstaller (remove.exe) + if FileExists(ExpandConstant('{app}\remove.exe')) then + begin + // Run the old uninstaller silently + if MsgBox('A previous version of Open Salamander was detected. Would you like to uninstall it first?', + mbConfirmation, MB_YESNO) = IDYES then + begin + Exec(ExpandConstant('{app}\remove.exe'), '/S', '', SW_SHOW, ewWaitUntilTerminated, ResultCode); + end; + end; + end; +end; diff --git a/Installer/x64 b/Installer/x64 deleted file mode 100644 index defd144d..00000000 --- a/Installer/x64 +++ /dev/null @@ -1 +0,0 @@ -This is a marker file for x64 installation. \ No newline at end of file diff --git a/README.md b/README.md index 662ac17e..e3d90c67 100644 --- a/README.md +++ b/README.md @@ -48,24 +48,37 @@ Solution ```\src\vcxproj\salamand.sln``` may be built from within Visual Studio Use ```\src\vcxproj\!populate_build_dir.cmd``` to populate build directory with files required to run Open Salamander. -### Creating SFX Installer +### Creating Installer -To create a standalone self-extracting installer (EXE) for distribution: +Open Salamander uses [Inno Setup](https://jrsoftware.org/isinfo.php) to create the installer. The installer script is located at `Installer\setup.iss`. -1. **Prepare files:** Ensure the `Installer` directory contains the latest build of `salamand.exe`, `salmon.exe`, and other required files. -2. **Run the script:** Use the provided PowerShell script in the `tools` directory. +#### Building Locally + +1. Install [Inno Setup 6](https://jrsoftware.org/isdl.php) or later +2. Build the solution in Release|x64 configuration +3. Stage the files and compile the installer: ```powershell -# Run from the project root -.\tools\Create-Sfx.ps1 -SourceDir "Installer" -OutputPath "OpenSalamander_Setup.exe" +# Stage files for the installer +.\tools\prepare_installer.ps1 -BuildDir "build_stage" -StagingDir "Installer_Staging" + +# Compile the installer +& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "Installer\setup.iss" ``` -The script automatically: +The installer will be created in `Installer\Output\`. + +#### GitHub Actions CI/CD + +The repository includes a GitHub Actions workflow (`.github\workflows\build-installer.yml`) that automatically: + +1. Builds the solution using MSBuild +2. Stages all required files (executables, plugins, language files, toolbars) +3. Installs Inno Setup via Chocolatey +4. Compiles the installer with build number versioning +5. Creates a GitHub release with the installer attached -- Compiles a C# bootstrap (stub) for extraction. -- Includes the latest SVG icons from `src\res\toolbars`. -- Modifies `setup.inf` (internally in the package) if necessary to ensure icons are installed. -- Produces a single `OpenSalamander_Setup.exe`. +The workflow is triggered on pushes to `master` and produces versioned installers named `OpenSalamander_5.0.{build_number}.exe`. ## Customization diff --git a/src/setup/doinst.c b/src/setup/doinst.c deleted file mode 100644 index 76e8f7a5..00000000 --- a/src/setup/doinst.c +++ /dev/null @@ -1,3010 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "precomp.h" -#include -#include -#include -#include - -#include "resource.h" -#include "infinst.h" -#include "remove\ctxmenu.h" - -#define COPY_FLAG_NOREMOVE 0x00000001 // will not be added to the uninstall log -//#define COPY_FLAG_DELAY_ENABLED 0x00000002 // if the target is open, perform a delayed copy -#define COPY_FLAG_FORCE_OVERWRITE 0x00000004 // unconditionally overwrites the target, no matter what it is -#define COPY_FLAG_DONT_OVERWRITE 0x00000008 // does not overwrite the target if it is newer -#define COPY_FLAG_TEST_CONFLICT 0x00000010 // checks for the existence of a previous (different) version -#define COPY_FLAG_SKIP_SAME 0x00000020 // skip identical files without asking - -DWORD InstallFinish(BOOL DoRunOnce); - -static WCHAR* AllocWideFromUtf8(const char* src) -{ - if (src == NULL) - return NULL; - int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0); - if (len <= 0) - return NULL; - WCHAR* buf = (WCHAR*)malloc(len * sizeof(WCHAR)); - if (buf == NULL) - return NULL; - if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, buf, len) == 0) - { - free(buf); - return NULL; - } - return buf; -} - -static DWORD GetFileAttributesUtf8Local(const char* fileName) -{ - DWORD attrs = INVALID_FILE_ATTRIBUTES; - WCHAR* fileNameW = AllocWideFromUtf8(fileName); - if (fileNameW == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return attrs; - } - attrs = GetFileAttributesW(fileNameW); - free(fileNameW); - return attrs; -} - -static BOOL CreateDirectoryUtf8Local(const char* dirName, LPSECURITY_ATTRIBUTES securityAttributes) -{ - BOOL ok = FALSE; - WCHAR* dirNameW = AllocWideFromUtf8(dirName); - if (dirNameW == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - ok = CreateDirectoryW(dirNameW, securityAttributes); - free(dirNameW); - return ok; -} - -static BOOL SetFileAttributesUtf8Local(const char* fileName, DWORD attrs) -{ - BOOL ok = FALSE; - WCHAR* fileNameW = AllocWideFromUtf8(fileName); - if (fileNameW == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - ok = SetFileAttributesW(fileNameW, attrs); - free(fileNameW); - return ok; -} - -static BOOL RemoveDirectoryUtf8Local(const char* dirName) -{ - BOOL ok = FALSE; - WCHAR* dirNameW = AllocWideFromUtf8(dirName); - if (dirNameW == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - ok = RemoveDirectoryW(dirNameW); - free(dirNameW); - return ok; -} - -// sections -const char* INF_PRIVATE_SECTION = "Private"; -const char* INF_COPYSECTION = "CopyFiles"; -const char* INF_SHORTCUTSECTION = "CreateShortcuts"; -const char* INF_CREATEDIRSSECTION = "CreateDirs"; -const char* INF_CREATEREGKEYS = "AddRegistryKeys"; -const char* INF_CREATEREGVALUES = "AddRegistryValues"; -const char* INF_GETREGVAR = "GetRegistryVar"; - -// items -const char* INF_APPNAME = "ApplicationName"; -const char* INF_APPNAMEVER = "ApplicationNameVer"; -const char* INF_DEFDIR = "DefaultDirectory"; -//const char *INF_USELASTDIR = "UseLastDirectory"; -const char* INF_LASTDIRS = "LastDirectories"; -const char* INF_VIEWREADME = "ViewReadme"; -const char* INF_RUNPROGRAM = "RunProgram"; -const char* INF_RUNPROGRAMQUIET = "RunProgramQuiet"; -const char* INF_INCREMENTFILECONTENTSRC = "IncrementFileContentSrc"; -const char* INF_INCREMENTFILECONTENTDST = "IncrementFileContentDst"; -const char* INF_ENSURESALAMANDER25DIR = "EnsureSalamander25Dir"; -const char* INF_UNINSTALLRUNPROGRAMQUIET = "UninstallRunProgramQuiet"; -const char* INF_SAVEREMOVELOG = "SaveRemoveLog"; -const char* INF_LICENSEFILE = "LicenseFile"; -const char* INF_LICENSEFILECZ = "LicenseFileCZ"; -const char* INF_FIRSTREADME = "FirstReadmeFile"; -const char* INF_SKIPCHOOSEDIR = "SkipChooseDirectory"; -const char* INF_CHECKCOMMONCONTROLS = "CheckCommonControls"; -const char* INF_CHECKRUNNINGAPPS = "CheckRunningApps"; -const char* INF_DELREGVALUES = "DelRegistryValues"; -const char* INF_DELREGKEYS = "DelRegistryKeys"; -const char* INF_DELFILES = "DelFiles"; -const char* INF_DELEMPTYDIRS = "DelEmptyDirs"; -const char* INF_DELSHELLEXTS = "DelShellExts"; -const char* INF_LOADOLDREMOVELOG = "LoadOldRemoveLog"; -const char* INF_AUTOIMPORTCONFIG = "AutoImportConfig"; -const char* INF_DISPLAYWELCOMEWARNING = "DisplayWelcomeWarning"; -const char* INF_SLGLANGUAGES = "SLGLanguages"; -const char* INF_WERLOCALDUMPS = "WERLocalDumps"; - -const char* INF_FILENAME = "\\setup.inf"; - -char ModulePath[MAX_PATH] = {0}; -char WindowsDirectory[MAX_PATH] = {0}; -char SystemDirectory[MAX_PATH] = {0}; -char ProgramFilesDirectory[MAX_PATH] = {0}; - -char DesktopDirectory[MAX_PATH] = {0}; -char StartMenuDirectory[MAX_PATH] = {0}; -char StartMenuProgramDirectory[MAX_PATH] = {0}; -char QuickLaunchDirectory[MAX_PATH] = {0}; - -char InfFileName[MAX_PATH]; - -DWORD CCMajorVer = 0; -DWORD CCMinorVer = 0; -DWORD CCMajorVerNeed = 0; -DWORD CCMinorVerNeed = 0; - -char CmdLineDestination[MAX_PATH] = {0}; - -BOOL ContainsPathUpgradableVersion(const char* path); -BOOL IncrementFileContent(); - -//BOOL AfterRebootCopy(const char *sFileName, const char *tFileName); - -//**************************************************************************** -// -// MyStrToDWORD -// - -DWORD -MyStrToDWORD(const char* num) -{ - const char* p = num; - const char* iter; - int len; - DWORD ret = 0; - int rad; - - while (*p == ' ') - p++; - - len = lstrlen(p); - if (len > 0) - { - rad = 1; - iter = p + len - 1; - while (iter >= p) - { - if (*iter < '0' || *iter > '9') - return 0; - ret += (*iter - '0') * rad; - iter--; - rad *= 10; - } - } - return ret; -} - -//**************************************************************************** -// -// HandleError -// - -int HandleError(int titleID, int messageID, unsigned long err) -{ - char title[500]; - char message[1000]; - LoadString(GetModuleHandle(NULL), titleID, title, 500); - LoadString(GetModuleHandle(NULL), messageID, message, 1000); - if (err) - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), message + lstrlen(message), - 1000 - lstrlen(message), NULL); - if (!SetupInfo.Silent) - MessageBox(HWizardDialog, message, title, MB_OK | MB_ICONEXCLAMATION); - return 1; -} - -int HandleErrorM(int titleID, const char* msg, unsigned long err) -{ - char title[500]; - char message[1000]; - lstrcpyn(message, msg, 1000); - LoadString(GetModuleHandle(NULL), titleID, title, 500); - if (err) - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), message + lstrlen(message), - 1000 - lstrlen(message), NULL); - - if (!SetupInfo.Silent) - MessageBox(HWizardDialog, message, title, MB_OK | MB_ICONEXCLAMATION); - return 1; -} - -// **************************************************************************** - -const char* MyLStrChr(const char* str, char chr) -{ - const char* iter; - iter = str; - while (*iter != 0 && *iter != chr) - iter++; - if (*iter != 0) - return iter; - return NULL; -} - -const char* MyRStrChr(const char* str, char chr) -{ - const char* iter; - iter = str + lstrlen(str); - while (iter >= str && *iter != chr) - iter--; - if (iter >= str && *iter == chr) - return iter; - return NULL; -} - -void MyCopyMemory(PVOID dst, CONST VOID* src, DWORD len) -{ - DWORD i; - for (i = 0; i < len; i++) - { - *((BYTE*)dst) = *((BYTE*)src); - ((BYTE*)dst)++; - ((BYTE*)src)++; - } -} - -int MyMemCmp(CONST VOID* src1, CONST VOID* src2, DWORD len) -{ - DWORD i; - for (i = 0; i < len; i++) - { - if (*((BYTE*)src1) != *((BYTE*)src2)) - return 1; - } - return 0; -} - -BOOL CheckAndCreateDirectory(const char* dir) -{ - BOOL quiet = TRUE; - DWORD attrs = GetFileAttributesUtf8Local(dir); - char buf[MAX_PATH + 100]; - char name[MAX_PATH]; - if (attrs == INVALID_FILE_ATTRIBUTES) // probably does not exist, allow it to be created - { - char root[MAX_PATH]; - GetRootPath(root, dir); - if (lstrlen(dir) <= lstrlen(root)) // directory is the root directory - { - if (!SetupInfo.Silent) - { - wsprintf(buf, LoadStr(IDS_CREATEDIRFAILED), dir); - MessageBox(HWizardDialog, buf, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - } - return FALSE; - } - // wsprintf(buf, LoadStr(IDS_CREATEDIRECTORY), dir); - if (quiet) - { - char* s; - const char* st; - int len; - - lstrcpy(name, dir); - while (1) // find the first existing directory - { - s = strrchr(name, '\\'); - if (s == NULL) - { - if (!SetupInfo.Silent) - { - wsprintf(buf, LoadStr(IDS_CREATEDIRFAILED), dir); - MessageBox(HWizardDialog, buf, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - } - return FALSE; - } - if (s - name > (int)lstrlen(root)) - *s = 0; - else - { - lstrcpy(name, root); - break; // already at the root directory - } - attrs = GetFileAttributesUtf8Local(name); - if (attrs != INVALID_FILE_ATTRIBUTES) // name exists - { - if (attrs & FILE_ATTRIBUTE_DIRECTORY) - break; // we will build from this directory - else // it's a file, that would not work ... - { - if (!SetupInfo.Silent) - { - wsprintf(buf, LoadStr(IDS_NAMEUSEDFORFILE), name); - MessageBox(HWizardDialog, buf, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - } - return FALSE; - } - } - } - s = name + lstrlen(name) - 1; - if (*s != '\\') - { - *++s = '\\'; - *++s = 0; - } - st = dir + lstrlen(name); - if (*st == '\\') - st++; - len = lstrlen(name); - while (*st != 0) - { - const char* slash = MyLStrChr(st, '\\'); - if (slash == NULL) - slash = st + lstrlen(st); - MyCopyMemory(name + len, st, (int)(slash - st)); - name[len += (int)(slash - st)] = 0; - while (1) - { - if (!CreateDirectoryUtf8Local(name, NULL)) - { - if (!SetupInfo.Silent) - { - wsprintf(buf, LoadStr(IDS_CREATEDIRFAILED), name); - if (MessageBox(HWizardDialog, buf, MAINWINDOW_TITLE, MB_RETRYCANCEL | MB_ICONEXCLAMATION) == IDCANCEL) - return FALSE; - } - else - return FALSE; - } - else - break; // done - } - name[len++] = '\\'; - if (*slash == '\\') - slash++; - st = slash; - } - return TRUE; - } - return FALSE; - } - if (attrs & FILE_ATTRIBUTE_DIRECTORY) - return TRUE; - else // it's a file, that would not work ... - { - if (!SetupInfo.Silent) - { - wsprintf(buf, LoadStr(IDS_NAMEUSEDFORFILE), dir); - MessageBox(HWizardDialog, buf, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - } - return FALSE; - } -} - -// -// **************************************************************************** - -struct VS_VERSIONINFO_HEADER_TAG -{ - WORD wLength; - WORD wValueLength; - WORD wType; -}; - -typedef struct VS_VERSIONINFO_HEADER_TAG VS_VERSIONINFO_HEADER; - -BOOL GetModuleVersion(HINSTANCE hModule, DWORD* major, DWORD* minor) -{ - HRSRC hRes; - HGLOBAL hVer; - DWORD resSize; - const BYTE* first; - const BYTE* iterator; - DWORD signature; - VS_FIXEDFILEINFO* ffi; - - hRes = FindResource(hModule, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); - if (hRes == NULL) - return FALSE; - - hVer = LoadResource(hModule, hRes); - if (hVer == NULL) - return FALSE; - - resSize = SizeofResource(hModule, hRes); - first = (BYTE*)LockResource(hVer); - if (resSize == 0 || first == 0) - return FALSE; - - iterator = first + sizeof(VS_VERSIONINFO_HEADER); - - signature = 0xFEEF04BD; - - while (MyMemCmp(iterator, &signature, 4) != 0) - { - iterator++; - if (iterator + 4 >= first + resSize) - return FALSE; - } - - ffi = (VS_FIXEDFILEINFO*)iterator; - - *major = ffi->dwFileVersionMS; - *minor = ffi->dwFileVersionLS; - - return TRUE; -} - -//**************************************************************************** -// -// QueryOverwrite -// - -// QueryOverwrite: "Overwrite" dialog for the copy-file routine -// if it succeeds, it returns the following values in the result variable: -#define CFQO_YES 0 -#define CFQO_YESALL 1 -#define CFQO_SKIP 2 -#define CFQO_SKIPALL 3 -#define CFQO_CANCEL 4 -/* -BOOL QueryOverwrite(const char *sFileName, const char *sourceAttr, - const char *tFileName, const char *targetAttr, int *result); -INT_PTR CALLBACK QueryOverwriteDlgProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam); -*/ -struct CFQOInternalTag -{ - const char* sFileName; - const char* sourceAttr; - const char* tFileName; - const char* targetAttr; -}; - -typedef struct CFQOInternalTag CFQOInternal; - -INT_PTR CALLBACK QueryOverwriteDlgProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - CFQOInternal* data = (CFQOInternal*)lParam; - - // center the dialog on the screen - CenterWindow(hWindow); - - // set the strings - SetDlgItemText(hWindow, IDC_CF_SOURCEFILENAME, data->sFileName); - SetDlgItemText(hWindow, IDC_CF_SOURCEFILEATTR, data->sourceAttr); - SetDlgItemText(hWindow, IDC_CF_TARGETFILENAME, data->tFileName); - SetDlgItemText(hWindow, IDC_CF_TARGETFILEATTR, data->targetAttr); - return TRUE; - } - - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDOK: - case IDCANCEL: - case IDC_CF_YESALL: - case IDC_CF_SKIP: - case IDC_CF_SKIPALL: - { - EndDialog(hWindow, LOWORD(wParam)); - return TRUE; - } - } - break; - } - } - return FALSE; -} - -BOOL QueryOverwrite(const char* sFileName, const char* sourceAttr, - const char* tFileName, const char* targetAttr, int* result) -{ - INT_PTR dlgRet; - CFQOInternal data; - data.sFileName = sFileName; - data.sourceAttr = sourceAttr; - data.tFileName = tFileName; - data.targetAttr = targetAttr; - - dlgRet = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CF_OVERWRITE), - HProgressDialog, QueryOverwriteDlgProc, (LPARAM)&data); - if (dlgRet == -1) - { - HandleError(IDS_MAINWINDOWTITLE, ERROR_DLGCREATE, GetLastError()); - return FALSE; - } - - switch (dlgRet) - { - case IDOK: - *result = CFQO_YES; - break; - case IDCANCEL: - *result = CFQO_CANCEL; - break; - case IDC_CF_YESALL: - *result = CFQO_YESALL; - break; - case IDC_CF_SKIP: - *result = CFQO_SKIP; - break; - case IDC_CF_SKIPALL: - *result = CFQO_SKIPALL; - break; - default: - *result = CFQO_CANCEL; - } - return TRUE; -} - -//**************************************************************************** -// -// QueryRetry -// - -struct CFQRInternalTag -{ - const char* sFileName; - DWORD Error; -}; - -typedef struct CFQRInternalTag CFQRInternal; - -INT_PTR CALLBACK QueryRetryDlgProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - char buff[1024]; - CFQRInternal* data; - data = (CFQRInternal*)lParam; - - // center the dialog on the screen - CenterWindow(hWindow); - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, data->Error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buff, - 1024, NULL); - - // set the strings - SetDlgItemText(hWindow, IDC_CF_RETRYNAME, data->sFileName); - SetDlgItemText(hWindow, IDC_CF_RETRYERROR, buff); - return TRUE; - } - - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDOK: - case IDCANCEL: - case IDC_CF_SKIP: - case IDC_CF_SKIPALL: - { - EndDialog(hWindow, LOWORD(wParam)); - return TRUE; - } - } - break; - } - } - return FALSE; -} - -BOOL QueryRetry(const char* sFileName, DWORD error, int* result) -{ - INT_PTR dlgRet; - CFQRInternal data; - data.sFileName = sFileName; - data.Error = error; - - dlgRet = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CF_RETRY), - HProgressDialog, QueryRetryDlgProc, (LPARAM)&data); - if (dlgRet == -1) - { - HandleError(IDS_MAINWINDOWTITLE, ERROR_DLGCREATE, GetLastError()); - return FALSE; - } - - switch (dlgRet) - { - case IDOK: - *result = CFQO_YES; - break; - case IDCANCEL: - *result = CFQO_CANCEL; - break; - case IDC_CF_SKIP: - *result = CFQO_SKIP; - break; - case IDC_CF_SKIPALL: - *result = CFQO_SKIPALL; - break; - default: - *result = CFQO_CANCEL; - } - return TRUE; -} - -//**************************************************************************** -// -// GetComCtlVersion -// - -// copies the file from sFileName into tFileName -// if the target file already exists, the overwrite variable is set -// and skip; if the overwrite variable is set, it does not ask about overwriting -// if the skip variable is set, the file is skipped -// on error returns FALSE - options then have no meaning -// on successful completion returns TRUE and the options variable -// is set according to how the operation was performed - -#define COPYFILEOPTIONS_NONE 0 -#define COPYFILEOPTIONS_OVERWRITE 1 -#define COPYFILEOPTIONS_OVERWRITEALL 2 -#define COPYFILEOPTIONS_SKIP 3 -#define COPYFILEOPTIONS_SKIPALL 4 -#define COPYFILEOPTIONS_CANCEL 5 -#define COPYFILEOPTIONS_SKIP_CREATE 6 -#define COPYFILEOPTIONS_SKIPALL_CREATE 7 -#define COPYFILEOPTIONS_SUCCESS 8 - -#define COPYBUFFER_MAX 50000 - -BOOL FileExist(const char* fileName) -{ - DWORD attr = GetFileAttributesUtf8Local(fileName); - if (attr == INVALID_FILE_ATTRIBUTES) - return FALSE; - return TRUE; - /* - // this does not work on a network drive (tested under NT 4.0) - HANDLE hFile = CreateFile(fileName, 0, 0, - NULL, OPEN_EXISTING, 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) - { - return FALSE; - } - else - { - CloseHandle(hFile); - return TRUE; - } - */ -} - -BOOL IsSameFile(const char* src, const char* dst) -{ - DWORD srcMajor, srcMinor; - DWORD dstMajor, dstMinor; - HINSTANCE hSrc, hDst; - - hSrc = LoadLibraryEx(src, NULL, LOAD_LIBRARY_AS_DATAFILE); - hDst = LoadLibraryEx(dst, NULL, LOAD_LIBRARY_AS_DATAFILE); - if (hSrc != NULL && hDst != NULL) - { - if (GetModuleVersion(hSrc, &srcMajor, &srcMinor) && GetModuleVersion(hDst, &dstMajor, &dstMinor)) - { - if (srcMajor == dstMajor && srcMinor == dstMinor) - { - FreeLibrary(hSrc); - FreeLibrary(hDst); - return TRUE; - } - } - } - if (hSrc != NULL) - FreeLibrary(hSrc); - if (hDst != NULL) - FreeLibrary(hDst); - return FALSE; -} - -BOOL MyCopyFile(const char* sFileName, const char* tFileName, - BOOL overwrite, BOOL skip, BOOL skipCreate, int* options, - DWORD flags) -{ - HANDLE hSourceFile = NULL; - HANDLE hTargetFile = NULL; - char buff[1000]; // for messages - char copyBuffer[COPYBUFFER_MAX]; // for the actual copying - DWORD read; - DWORD fileAtttr; - - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - - *options = COPYFILEOPTIONS_NONE; - - // try to open the source file - hSourceFile = CreateFile(sFileName, GENERIC_READ, - FILE_SHARE_READ, NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - if (hSourceFile == INVALID_HANDLE_VALUE) - { - // failed - bail out - DWORD error = GetLastError(); - wsprintf(buff, LoadStr(ERROR_CF_OPENFILE), sFileName); - HandleErrorM(IDS_MAINWINDOWTITLE, buff, error); - return FALSE; - } - - // if we are not forcing overwrite and the target file exists, we must ask - // about overwriting it - if (!overwrite) - { - if (FileExist(tFileName)) - { - BY_HANDLE_FILE_INFORMATION sourceInformation; - BY_HANDLE_FILE_INFORMATION targetInformation; - FILETIME ft; - SYSTEMTIME st; - int result; - - if (skip) - { - return TRUE; - } - - hTargetFile = CreateFile(tFileName, 0, 0, NULL, OPEN_EXISTING, 0, NULL); - if (hTargetFile == INVALID_HANDLE_VALUE) - { - // this should never happen; moments ago I opened it in the same mode - DWORD error = GetLastError(); - wsprintf(buff, LoadStr(ERROR_CF_OPENFILE), tFileName); - HandleErrorM(IDS_MAINWINDOWTITLE, buff, error); - CloseHandle(hSourceFile); - return FALSE; - } - - if (!GetFileInformationByHandle(hSourceFile, &sourceInformation)) - { - DWORD error = GetLastError(); - wsprintf(buff, LoadStr(ERROR_CF_FILEINFORMATION), sFileName); - HandleErrorM(IDS_MAINWINDOWTITLE, buff, error); - CloseHandle(hSourceFile); - CloseHandle(hTargetFile); - return FALSE; - } - - if (!GetFileInformationByHandle(hTargetFile, &targetInformation)) - { - DWORD error = GetLastError(); - wsprintf(buff, LoadStr(ERROR_CF_FILEINFORMATION), tFileName); - HandleErrorM(IDS_MAINWINDOWTITLE, buff, error); - CloseHandle(hSourceFile); - CloseHandle(hTargetFile); - return FALSE; - } - CloseHandle(hTargetFile); - - if (!(flags & COPY_FLAG_FORCE_OVERWRITE)) - { - BOOL testTime = TRUE; - - if (flags & COPY_FLAG_SKIP_SAME) - { - // if the file has the same size and version, skip it - // try to load both modules - if (sourceInformation.nFileSizeLow == targetInformation.nFileSizeLow && IsSameFile(sFileName, tFileName)) - { - result = CFQO_SKIP; - testTime = FALSE; - } - } - - // if the file being overwritten is newer and COPY_FLAG_FORCE_OVERWRITE is not set, - // ask the user - if (testTime) - { - if (CompareFileTime(&sourceInformation.ftLastWriteTime, &targetInformation.ftLastWriteTime) == -1) - { - if (!(flags & COPY_FLAG_DONT_OVERWRITE)) - { - char sourceAttr[200]; - char targetAttr[200]; - wsprintf(sourceAttr, "%d, ", sourceInformation.nFileSizeLow); - FileTimeToLocalFileTime(&sourceInformation.ftLastWriteTime, &ft); - FileTimeToSystemTime(&ft, &st); - if (GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, - sourceAttr + lstrlen(sourceAttr), 50) == 0) - wsprintf(sourceAttr + lstrlen(sourceAttr), "%d.%d.%d", st.wDay, st.wMonth, st.wYear); - lstrcat(sourceAttr, ", "); - if (GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, - sourceAttr + lstrlen(sourceAttr), 50) == 0) - wsprintf(sourceAttr + lstrlen(sourceAttr), "%d:%02d:%02d", st.wHour, st.wMinute, st.wSecond); - - wsprintf(targetAttr, "%d, ", targetInformation.nFileSizeLow); - FileTimeToLocalFileTime(&targetInformation.ftLastWriteTime, &ft); - FileTimeToSystemTime(&ft, &st); - if (GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, - targetAttr + lstrlen(targetAttr), 50) == 0) - wsprintf(targetAttr + lstrlen(targetAttr), "%d.%d.%d", st.wDay, st.wMonth, st.wYear); - lstrcat(targetAttr, ", "); - if (GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, - targetAttr + lstrlen(targetAttr), 50) == 0) - wsprintf(targetAttr + lstrlen(targetAttr), "%d:%02d:%02d", st.wHour, st.wMinute, st.wSecond); - if (!QueryOverwrite(sFileName, sourceAttr, tFileName, targetAttr, &result)) - { - CloseHandle(hSourceFile); - return FALSE; - } - } - else - result = CFQO_SKIP; - } - else - result = CFQO_YES; - } // else result is already set to CFQO_SKIP - } - else - result = CFQO_YES; - - switch (result) - { - case CFQO_YES: - *options = COPYFILEOPTIONS_OVERWRITE; - break; - case CFQO_YESALL: - *options = COPYFILEOPTIONS_OVERWRITEALL; - break; - case CFQO_SKIP: - *options = COPYFILEOPTIONS_SKIP; - break; - case CFQO_SKIPALL: - *options = COPYFILEOPTIONS_SKIPALL; - break; - case CFQO_CANCEL: - *options = COPYFILEOPTIONS_CANCEL; - break; - default: - *options = COPYFILEOPTIONS_CANCEL; - break; - } - - if (*options == COPYFILEOPTIONS_CANCEL || - *options == COPYFILEOPTIONS_SKIP || *options == COPYFILEOPTIONS_SKIPALL) - return TRUE; - - // only overwrite and overwrite all remain, so let's proceed - } - } - - if ((flags & COPY_FLAG_DONT_OVERWRITE) && (*options == COPYFILEOPTIONS_NONE)) - { - *options = COPYFILEOPTIONS_SUCCESS; - return TRUE; - } - - if (FileExist(tFileName)) - { - // override READONLY/SYSTEM/HIDDEN attributes - if (!SetFileAttributesUtf8Local(tFileName, FILE_ATTRIBUTE_ARCHIVE)) - { - DWORD error = GetLastError(); - wsprintf(buff, LoadStr(ERROR_CF_FILESETATTR), tFileName); - HandleErrorM(IDS_MAINWINDOWTITLE, buff, error); - CloseHandle(hSourceFile); - return FALSE; - } - } - - fileAtttr = GetFileAttributesUtf8Local(sFileName); - if (fileAtttr == INVALID_FILE_ATTRIBUTES) - { - HandleError(IDS_MAINWINDOWTITLE, ERROR_CF_GETATTR, GetLastError()); - CloseHandle(hSourceFile); - return FALSE; - } - - // open the output file for writing -CreateAgain: - hTargetFile = CreateFile(tFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, fileAtttr, NULL); - if (hTargetFile == INVALID_HANDLE_VALUE) - { - int result; - DWORD error = GetLastError(); - /* - if (flags & COPY_FLAG_DELAY_ENABLED && error == ERROR_SHARING_VIOLATION) - { - if (AfterRebootCopy(sFileName, tFileName)) - return TRUE; - } -*/ - if (skipCreate) - { - CloseHandle(hSourceFile); - return TRUE; - } - if (QueryRetry(tFileName, error, &result)) - { - switch (result) - { - case CFQO_YES: - goto CreateAgain; - break; - case CFQO_SKIP: - *options = COPYFILEOPTIONS_SKIP_CREATE; - break; - case CFQO_SKIPALL: - *options = COPYFILEOPTIONS_SKIPALL_CREATE; - break; - case CFQO_CANCEL: - *options = COPYFILEOPTIONS_CANCEL; - break; - } - CloseHandle(hSourceFile); - return TRUE; - } - - CloseHandle(hSourceFile); - return FALSE; - } - - // copy the contents of the source file into the target - do - { - if (!ReadFile(hSourceFile, copyBuffer, COPYBUFFER_MAX, &read, NULL)) - { - DWORD error = GetLastError(); - wsprintf(buff, LoadStr(ERROR_CF_READFILE), sFileName); - HandleErrorM(IDS_MAINWINDOWTITLE, buff, error); - CloseHandle(hTargetFile); - CloseHandle(hSourceFile); - return FALSE; - } - - if (read > 0) - { - DWORD written; - if (!WriteFile(hTargetFile, copyBuffer, read, &written, NULL) || read != written) - { - DWORD error = GetLastError(); - wsprintf(buff, LoadStr(ERROR_CF_WRITEFILE), tFileName); - HandleErrorM(IDS_MAINWINDOWTITLE, buff, error); - CloseHandle(hTargetFile); - CloseHandle(hSourceFile); - return FALSE; - } - } - } while (read == COPYBUFFER_MAX); - - // set the target file to the same timestamp as the source file - GetFileTime(hSourceFile, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime); - SetFileTime(hTargetFile, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime); - - CloseHandle(hTargetFile); - CloseHandle(hSourceFile); - - if (*options == COPYFILEOPTIONS_NONE) - *options = COPYFILEOPTIONS_SUCCESS; - - return TRUE; -} -/* -// moves the file into the target directory but under a temporary name -// schedules the target to be deleted after reboot and the source renamed to the target -// sets the RebootNeeded variable - -BOOL AfterRebootCopy(const char *sFileName, const char *tFileName) -{ - char tDirectory[MAX_PATH]; - char tTmpFileName[MAX_PATH]; - int options; - lstrcpy(tDirectory, tFileName); - - *(strrchr(tDirectory, '\\')) = '\0'; // Strip file name - if (GetTempFileName(tDirectory, "STP", 0, tTmpFileName) == 0) - return FALSE; - - options = COPYFILEOPTIONS_NONE; - if (!MyCopyFile(sFileName, tTmpFileName, TRUE, FALSE, FALSE, &options, 0)) - return FALSE; - - if (options != COPYFILEOPTIONS_SUCCESS) - return FALSE; - - if (SystemWindowsNT) - { - if (MoveFileEx(tTmpFileName, tFileName, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING) == 0) - return FALSE; - } - - SetupInfo.RebootNeeded = TRUE; - return TRUE; -} -*/ -//**************************************************************************** -// -// GetComCtlVersion -// - -HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) -{ - HINSTANCE hComCtl; - //load the DLL - hComCtl = LoadLibrary(TEXT("comctl32.dll")); - if (hComCtl) - { - HRESULT hr = S_OK; - DLLGETVERSIONPROC pDllGetVersion; - /* - You must get this function explicitly because earlier versions of the DLL - don't implement this function. That makes the lack of implementation of the - function a version marker in itself. - */ - pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hComCtl, TEXT("DllGetVersion")); - if (pDllGetVersion) - { - DLLVERSIONINFO dvi = {0}; - dvi.cbSize = sizeof(dvi); - hr = (*pDllGetVersion)(&dvi); - if (SUCCEEDED(hr)) - { - *pdwMajor = dvi.dwMajorVersion; - *pdwMinor = dvi.dwMinorVersion; - } - else - { - hr = E_FAIL; - } - } - else - { - /* - If GetProcAddress failed, then the DLL is a version previous to the one - shipped with IE 3.x. - */ - *pdwMajor = 4; - *pdwMinor = 0; - } - FreeLibrary(hComCtl); - return hr; - } - return E_FAIL; -} - -//************************************************************************************ -// -// CheckRunningApp -// -// checks whether an application with the window class appWindowClassName is running -// - -void CheckRunningApp(const char* appWindowClassName) -{ - HWND hWnd; - hWnd = FindWindow(appWindowClassName, NULL); - if (hWnd != NULL) - { - char windowName[100]; - char buff[2000]; - - GetWindowText(hWnd, windowName, 100); - wsprintf(buff, LoadStr(IDS_APPRUNNING), windowName); - - if (!SetupInfo.Silent) - MessageBox(NULL, buff, MAINWINDOW_TITLE, MB_OK | MB_ICONINFORMATION); - } -} - -//************************************************************************************ -// -// OpenInfFile -// - -BOOL OpenInfFile() -{ - HANDLE hFile; - DWORD read; - BOOL bResult = FALSE; - BOOL x64Mark; - BOOL x64x86Conflit = FALSE; - - lstrcpy(InfFileName, ModulePath); - lstrcat(InfFileName, "\\x64"); - x64Mark = FileExist(InfFileName); -#ifdef _WIN64 - if (!x64Mark) - x64x86Conflit = TRUE; -#else - if (x64Mark) - x64x86Conflit = TRUE; -#endif - if (x64x86Conflit) - { - MessageBox(NULL, "Internal x64/x86 conflict.", MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - return FALSE; - } - - lstrcpy(InfFileName, ModulePath); - lstrcat(InfFileName, INF_FILENAME); - - // load the INF file - hFile = CreateFile(InfFileName, GENERIC_READ, 0, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); - if (hFile == INVALID_HANDLE_VALUE) - { - if (!SetupInfo.Silent) - { - char buff[MAX_PATH]; - wsprintf(buff, LoadStr(ERROR_LOADINF), InfFileName); - MessageBox(NULL, buff, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - } - return FALSE; - } - - if (!ReadFile(hFile, SetupInfo.InfFile, sizeof(SetupInfo.InfFile), &read, NULL)) - { - if (!SetupInfo.Silent) - { - char buff[MAX_PATH]; - CloseHandle(hFile); - wsprintf(buff, LoadStr(ERROR_LOADINF), InfFileName); - MessageBox(NULL, buff, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - } - return FALSE; - } - CloseHandle(hFile); - - // extract the GetRegistryVar section - if (!DoGetRegistryVarSection()) - return FALSE; - - // if needed, verify the common controls version - SetupInfo.TmpSection[0] = 0; - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_CHECKCOMMONCONTROLS, "", - SetupInfo.TmpSection, MAX_PATH, InfFileName); - if (SetupInfo.TmpSection[0] != 0) - { - char* minorPtr; - - minorPtr = SetupInfo.TmpSection; - while (*minorPtr != 0 && *minorPtr != '.') - minorPtr++; - - if (*minorPtr == '.') - { - *minorPtr = 0; - minorPtr++; - CCMajorVerNeed = MyStrToDWORD(SetupInfo.TmpSection); - CCMinorVerNeed = MyStrToDWORD(minorPtr); - } - - GetComCtlVersion(&CCMajorVer, &CCMinorVer); - if (CCMajorVer < CCMajorVerNeed || (CCMajorVer == CCMajorVerNeed && CCMinorVer < CCMinorVerNeed)) - { - if (!SetupInfo.Silent) - DialogBox(HInstance, MAKEINTRESOURCE(IDD_COMMONCONTROL), NULL, CommonControlsDlgProc); - } - } - - // if needed, check running applications - SetupInfo.TmpSection[0] = 0; - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_CHECKRUNNINGAPPS, "", - SetupInfo.CheckRunningApps, MAX_PATH, InfFileName); - if (SetupInfo.CheckRunningApps[0] != 0 && !SetupInfo.Silent) - { - char appClass[1000]; - char* begin; - char* end; - - begin = end = SetupInfo.CheckRunningApps; - - while (*begin != 0) - { - while (*end != 0 && *end != ',') - end++; - lstrcpyn(appClass, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - begin = end; - - CheckRunningApp(appClass); - } - } - - // load the basic data - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_APPNAME, "", - SetupInfo.ApplicationName, MAX_PATH, InfFileName); - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_APPNAMEVER, SetupInfo.ApplicationName, - SetupInfo.ApplicationNameVer, MAX_PATH, InfFileName); - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_DEFDIR, "", - SetupInfo.DefaultDirectory, MAX_PATH, InfFileName); - - // GetPrivateProfileString(INF_PRIVATE_SECTION, INF_USELASTDIR, "", - // SetupInfo.UseLastDirectory, MAX_PATH, InfFileName); - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_LASTDIRS, "", - SetupInfo.LastDirectories, 3000, InfFileName); - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_SAVEREMOVELOG, "", - SetupInfo.SaveRemoveLog, MAX_PATH, InfFileName); - - if (GetCurDispLangID() == 1029 /* Czech */) // try the Czech version and, if it is missing, fall back to the English license - { - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_LICENSEFILECZ, "", - SetupInfo.LicenseFilePath, MAX_PATH, InfFileName); - if (SetupInfo.LicenseFilePath[0] == 0) - { - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_LICENSEFILE, "", - SetupInfo.LicenseFilePath, MAX_PATH, InfFileName); - } - } - else // only attempt to load the English version of the license - { - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_LICENSEFILE, "", - SetupInfo.LicenseFilePath, MAX_PATH, InfFileName); - } - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_FIRSTREADME, "", - SetupInfo.FirstReadmeFilePath, MAX_PATH, InfFileName); - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_UNINSTALLRUNPROGRAMQUIET, "", - SetupInfo.UnistallRunProgramQuietPath, MAX_PATH, InfFileName); - - SetupInfo.TmpSection[0] = 0; - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_SKIPCHOOSEDIR, "", - SetupInfo.TmpSection, MAX_PATH, InfFileName); - SetupInfo.SkipChooseDir = SetupInfo.TmpSection[0] == '1'; - - SetupInfo.TmpSection[0] = 0; - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_LOADOLDREMOVELOG, "", - SetupInfo.TmpSection, MAX_PATH, InfFileName); - SetupInfo.LoadOldRemoveLog = SetupInfo.TmpSection[0] == '1'; - - SetupInfo.TmpSection[0] = 0; - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_DISPLAYWELCOMEWARNING, "", - SetupInfo.TmpSection, MAX_PATH, InfFileName); - SetupInfo.DisplayWelcomeWarning = SetupInfo.TmpSection[0] == 0 ? 0 : MyStrToDWORD(SetupInfo.TmpSection); - - ExpandPath(SetupInfo.DefaultDirectory); - if (CmdLineDestination[0] != 0) - lstrcpy(SetupInfo.DefaultDirectory, CmdLineDestination); - ExpandPath(SetupInfo.LicenseFilePath); - - SetupInfo.UseFirstReadme = FALSE; - if (SetupInfo.FirstReadmeFilePath[0] != 0) - { - ExpandPath(SetupInfo.FirstReadmeFilePath); - if (LoadTextFile(SetupInfo.FirstReadmeFilePath, SetupInfo.FirstReadme, 100000)) - SetupInfo.UseFirstReadme = TRUE; - } - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_INCREMENTFILECONTENTSRC, "", - SetupInfo.IncrementFileContentSrc, 5000, InfFileName); - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_INCREMENTFILECONTENTDST, "", - SetupInfo.IncrementFileContentDst, 5000, InfFileName); - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_ENSURESALAMANDER25DIR, "", - SetupInfo.EnsureSalamander25Dir, 5000, InfFileName); - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_AUTOIMPORTCONFIG, "", - SetupInfo.AutoImportConfig, MAX_PATH, InfFileName); - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_SLGLANGUAGES, "", - SetupInfo.SLGLanguages, MAX_PATH, InfFileName); - - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_WERLOCALDUMPS, "", - SetupInfo.WERLocalDumps, MAX_PATH, InfFileName); - - SetupInfo.UseLicenseFile = lstrlen(SetupInfo.LicenseFilePath) > 0; - - ExtractCreateDirsSection(); - ExtractShortcutSection(); - ExtractCopySection(); - - if (CmdLineDestination[0] == 0 && !SetupInfo.Silent) - LoadLastDirectory(); // DefaultDirectory and UseLastDirectory are set - we can proceed - - return TRUE; -} - -BOOL MyGetPrivateProfileSection(const char* infFile, const char* section, char* buff, int buffMax) -{ - const char* p = infFile; - char* dst = buff; - while (*p != 0) - { - while (*p != '[' && *p != 0) - p++; - if (*p == '[') - { - const char* end = p + 1; - while (*end != ']' && *end != 0) - end++; - if (*end == ']') - { - char tmp[1024]; - const char* src = p + 1; - lstrcpyn(tmp, src, (int)(end - src + 1)); - if (lstrcmpi(tmp, section) == 0) - { - char line[1024]; - p = end + 1; - - while (*p != '[' && *p != 0) - { - while (*p == '\r' || *p == '\n') - p++; - end = p; - while (*end != '\r' && *end != '\n' && *end != 0) - end++; - - while (*p == ' ') - p++; - - lstrcpyn(line, p, (int)(end - p + 1)); - - if (*line != ';' && *line != 0) - { - int len; - lstrcpy(dst, line); - len = lstrlen(line); - dst += len + 1; - } - while (*end == '\r' || *end == '\n') - end++; - p = end; - } - *dst = 0; - return TRUE; - } - else - { - p = end + 1; - } - } - else - return FALSE; - } - else - return FALSE; - } - return FALSE; -} - -// if the line is not yet in the target, append it and terminate with two zeros -void RemoveAddLine(char* target, const char* line) -{ - char* p = target; - while (*p != 0) - { - if (lstrcmpi(p, line) == 0) - return; - p += lstrlen(p) + 1; - } - - lstrcpy(p, line); - p += lstrlen(line) + 1; - *p = 0; // final terminator -} - -//************************************************************************************ -// -// QueryFreeSpace -// - -BOOL QueryFreeSpace(char* driveSpec, LONGLONG* spaceRequired) -{ - /* - HDSKSPC hDskSpc; - char root[MAX_PATH]; - - lstrcpy(root, driveSpec); - if (root[lstrlen(root) - 1] == '\\') - root[lstrlen(root) - 1] = 0; - - - hDskSpc = SetupCreateDiskSpaceList(NULL, 0, 0); - if (hDskSpc == NULL) - return FALSE; - - if (!SetupAddInstallSectionToDiskSpaceList(hDskSpc, HInfFile, NULL, "Install", 0, 0)) - { - SetupDestroyDiskSpaceList(hDskSpc); - return FALSE; - } - - if (!SetupQuerySpaceRequiredOnDrive(hDskSpc, root, spaceRequired, NULL, 0)) - { - SetupDestroyDiskSpaceList(hDskSpc); - return FALSE; - } - SetupDestroyDiskSpaceList(hDskSpc); - */ - return TRUE; -} - -BOOL GetSpecialFolderPath(int folder, char* path) -{ - ITEMIDLIST* pidl; // select the root folder - *path = 0; - if (SUCCEEDED(SHGetSpecialFolderLocation(HWizardDialog, folder, &pidl))) - { - IMalloc* alloc; - SHGetPathFromIDList(pidl, path); - if (SUCCEEDED(CoGetMalloc(1, &alloc))) - { - if (alloc->lpVtbl->DidAlloc(alloc, pidl) == 1) - alloc->lpVtbl->Free(alloc, pidl); - alloc->lpVtbl->Release(alloc); - } - return TRUE; - } - return FALSE; -} - -// returns a pointer to the trailing %SLG (if it exists), otherwise returns NULL -char* FindSLGEnding(char* buff) -{ - int len = lstrlen(buff); - if (len < 4) - return NULL; - if (lstrcmp(buff + len - 4, "%SLG") != 0) - return NULL; - return buff + len - 4; -} - -int GetSLGNameLen(const char* buff) -{ - const char* p = buff; - while (*p != 0 && *p != ',') - p++; - return (int)(p - buff); -} - -void ExtractCopySection() -{ - char* line; - char src[MAX_PATH]; - char dst[MAX_PATH]; - //char size[100]; - char flags[100]; - char* from; - char* to; - char* srcSLGEnding; - char* dstSLGEnding; - BOOL expandLanguages; - const char* slgLang; - - SetupInfo.CopyFrom[0] = 0; - SetupInfo.CopyTo[0] = 0; - SetupInfo.CopyCount = 0; - // SetupInfo.SpaceRequired = 0; - - from = SetupInfo.CopyFrom; - to = SetupInfo.CopyTo; - - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_COPYSECTION, SetupInfo.CopySection, sizeof(SetupInfo.CopySection)); - line = SetupInfo.CopySection; - while (*line != 0) - { - char* begin; - char* end; - int len = lstrlen(line); - if (len > 0 && line[0] != ';') - { - BYTE flagsNum; - src[0] = 0; - dst[0] = 0; - //size[0] = 0; - flags[0] = 0; - begin = end = line; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(src, begin, (int)(end - begin + 1)); - - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(dst, begin, (int)(end - begin + 1)); - - /* we no longer retrieve the size - if (*end == ',') - end++; - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(size, begin, end - begin + 1); - */ - - flagsNum = 0; - if (*end == ',') - { - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(flags, begin, (int)(end - begin + 1)); - flagsNum = MyStrToDWORD(flags) & 0xFF; - } - - // verify whether src and dst both end with "%SLG"; if so, expand it - srcSLGEnding = FindSLGEnding(src); - dstSLGEnding = FindSLGEnding(dst); - expandLanguages = (srcSLGEnding != NULL && dstSLGEnding != NULL); - slgLang = expandLanguages ? SetupInfo.SLGLanguages : ""; - - do - { - SetupInfo.CopyFlags[SetupInfo.CopyCount] = flagsNum; - - if (expandLanguages) - { - int slgNameLen = GetSLGNameLen(slgLang); - lstrcpyn(srcSLGEnding, slgLang, slgNameLen + 1); - lstrcpyn(dstSLGEnding, slgLang, slgNameLen + 1); - slgLang += slgNameLen; - if (*slgLang == ',') - slgLang++; - } - - lstrcpy(from, src); - lstrcpy(to, dst); - from += lstrlen(src) + 1; - to += lstrlen(dst) + 1; - - SetupInfo.CopyCount++; - } while (*slgLang != 0); - } - line += len + 1; - } - // SetupInfo.SpaceRequired += 10000; // uninstall log :-))) what a hack, huh - *from = 0; - *to = 0; -} - -#define LT_NONE 0 -#define LT_DESKTOP 1 -#define LT_STARTMENU 2 -#define LT_QUICKLAUNCH 4 - -int GetLineType(const char* line) -{ - const char* p = line; - while (*p != 0) - { - if (*p == '%') - { - if (*(p + 1) == '5') - return LT_DESKTOP; - if (*(p + 1) == '7') - return LT_STARTMENU; - if (*(p + 1) == '8') - return LT_QUICKLAUNCH; - } - p++; - } - return LT_NONE; -} - -void ExtractShortcutSection() -{ - char* line; - - SetupInfo.DesktopPresent = FALSE; - SetupInfo.StartMenuPresent = FALSE; - - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_SHORTCUTSECTION, SetupInfo.ShortcutSection, sizeof(SetupInfo.ShortcutSection)); - line = SetupInfo.ShortcutSection; - while (*line != 0) - { - int len = lstrlen(line); - if (len > 0 && line[0] != ';') - { - int type = GetLineType(line); - if (type == LT_DESKTOP) - SetupInfo.DesktopPresent = TRUE; - if (type == LT_STARTMENU) - SetupInfo.StartMenuPresent = TRUE; - } - line += len + 1; - } -} - -HRESULT -CreateShortCut(LPCSTR pszShortcutFile, LPSTR pszLink, LPSTR pszDesc) -{ - HRESULT hres; - IShellLink* psl; - - hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - &IID_IShellLink, (void**)&psl); - if (SUCCEEDED(hres)) - { - IPersistFile* ppf; - hres = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (void**)&ppf); - if (SUCCEEDED(hres)) - { - WORD wsz[MAX_PATH]; // buffer for Unicode string - hres = psl->lpVtbl->SetPath(psl, pszShortcutFile); - hres = psl->lpVtbl->SetDescription(psl, pszDesc); - - MultiByteToWideChar(CP_ACP, 0, pszLink, -1, wsz, MAX_PATH); - - hres = ppf->lpVtbl->Save(ppf, wsz, TRUE); - if (SUCCEEDED(hres)) - RemoveAddLine(SetupInfo.RemoveFiles, pszLink); - - if (!SUCCEEDED(hres)) - { - } - - ppf->lpVtbl->Release(ppf); - } - psl->lpVtbl->Release(psl); - } - return hres; -} - -//void -//PinToTaskbar(const char *pszLink) -//{ -// if (InvokeCmdFromContextMenu(HWizardDialog, pszLink, "taskbarpin")) -// RemoveAddLine(SetupInfo.UnpinFromTaskbar, pszLink); -//} - -BOOL CreateShortcuts() -{ - HRESULT hres; - char* line; - char src[MAX_PATH]; - char dst[MAX_PATH]; - char des[MAX_PATH]; - - if (!SetupInfo.DesktopPresent && !SetupInfo.StartMenuPresent) - return TRUE; - - OleInitialize(NULL); - - line = SetupInfo.ShortcutSection; - while (*line != 0) - { - char* begin; - char* end; - - int len = lstrlen(line); - int type = GetLineType(line); - - if (!(type == LT_DESKTOP && !SetupInfo.ShortcutInDesktop || - type == LT_STARTMENU && !SetupInfo.ShortcutInStartMenu || - type == LT_QUICKLAUNCH)) - { - src[0] = 0; - dst[0] = 0; - des[0] = 0; - - begin = end = line; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(src, begin, (int)(end - begin + 1)); - - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(dst, begin, (int)(end - begin + 1)); - - if (*end == ',') - end++; - - lstrcpyn(des, end, MAX_PATH); - - ExpandPath(src); - ExpandPath(dst); - ExpandPath(des); - - hres = CreateShortCut(src, dst, des); - if (hres != ERROR_SUCCESS) - { - char buff[200 + MAX_PATH]; - // it failed - report it to the user so they know what's going on - wsprintf(buff, LoadStr(ERROR_CREATESHORTCUT), hres, dst); - HandleErrorM(IDS_MAINWINDOWTITLE, buff, hres == 0x80004005 ? ERROR_ACCESS_DENIED : hres); - } - else - { - //if (SetupInfo.PinToTaskbar && type == LT_STARTMENU) - // PinToTaskbar(dst); - } - } - line += len + 1; - } - - OleUninitialize(); - - return TRUE; -} - -void ExtractCreateDirsSection() -{ - char* line; - - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_CREATEDIRSSECTION, SetupInfo.CreateDirsSection, sizeof(SetupInfo.CreateDirsSection)); - line = SetupInfo.CreateDirsSection; - - SetupInfo.CreateDirsCount = 0; - while (*line != 0) - { - int len = lstrlen(line); - if (len > 0 && line[0] != ';') - { - SetupInfo.CreateDirsCount++; - } - line += len + 1; - } -} - -BOOL CreateDirs() -{ - char* line; - char dir[MAX_PATH]; - - line = SetupInfo.CreateDirsSection; - while (*line != 0) - { - int len = lstrlen(line); - - int type = GetLineType(line); - if (!(type == LT_DESKTOP && !SetupInfo.ShortcutInDesktop || - type == LT_STARTMENU && !SetupInfo.ShortcutInStartMenu || - type == LT_QUICKLAUNCH)) - { - lstrcpy(dir, line); - ExpandPath(dir); - - if (!CheckAndCreateDirectory(dir)) - return FALSE; - RemoveAddLine(SetupInfo.RemoveDirs, dir); - } - - line += len + 1; - } - - return TRUE; -} - -HKEY GetRootHandle(const char* root) -{ - if (lstrcmpi(root, "HKLM") == 0) - return HKEY_LOCAL_MACHINE; - if (lstrcmpi(root, "HKCU") == 0) - return HKEY_CURRENT_USER; - if (lstrcmpi(root, "HKCC") == 0) - return HKEY_CURRENT_CONFIG; - if (lstrcmpi(root, "HKCR") == 0) - return HKEY_CLASSES_ROOT; - return NULL; -} - -BOOL GetRegistryDWORDValue(const char* line, DWORD* retVal) -{ - HKEY hRoot; - HKEY hKey; - const char* begin; - const char* end; - char root[MAX_PATH]; - char key[MAX_PATH]; - char value[MAX_PATH]; - BOOL ret = FALSE; - - begin = end = line; - - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(value, begin, (int)(end - begin + 1)); - - hRoot = GetRootHandle(root); - if (RegOpenKeyEx(hRoot, key, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) - { - DWORD dwDataSize; - DWORD dwType; - dwDataSize = sizeof(DWORD); - dwType = REG_DWORD; - if (RegQueryValueEx(hKey, value, 0, &dwType, (LPBYTE)retVal, &dwDataSize) == ERROR_SUCCESS) - ret = TRUE; - RegDeleteValue(hKey, value); - RegCloseKey(hKey); - } - return ret; -} - -BOOL DelRegistryValue(const char* line) -{ - HKEY hRoot; - HKEY hKey; - const char* begin; - const char* end; - char root[MAX_PATH]; - char key[MAX_PATH]; - char value[MAX_PATH]; - - begin = end = line; - - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(value, begin, (int)(end - begin + 1)); - - hRoot = GetRootHandle(root); - if (RegOpenKeyEx(hRoot, key, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) - { - RegDeleteValue(hKey, value); - RegCloseKey(hKey); - } - return TRUE; -} - -BOOL DelRegistryValues() -{ - char* line; - SetupInfo.TmpSection[0] = 0; - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_DELREGVALUES, SetupInfo.TmpSection, sizeof(SetupInfo.TmpSection)); - line = SetupInfo.TmpSection; - while (*line != 0) - { - int len = lstrlen(line); - if (len > 0) - DelRegistryValue(line); - line += len + 1; - } - return TRUE; -} - -//************************************************************************************ -// -// RemoveAllSubKeys -// - -BOOL RemoveAllSubKeys(HKEY hKey) -{ - char buff[MAX_PATH]; - while (RegEnumKey(hKey, 0, buff, MAX_PATH) != ERROR_NO_MORE_ITEMS) - { - HKEY hSubKey; - if (RegOpenKey(hKey, buff, &hSubKey) == ERROR_SUCCESS) - { - RemoveAllSubKeys(hSubKey); - RegCloseKey(hSubKey); - RegDeleteKey(hKey, buff); - } - } - return TRUE; -} - -//************************************************************************************ -// -// DelRegistryKey -// - -BOOL DelRegistryKey(const char* line) -{ - HKEY hSubKey; - HKEY hRoot; - const char* begin; - const char* end; - char root[MAX_PATH]; - char key[MAX_PATH]; - - begin = end = line; - - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - hRoot = GetRootHandle(root); - if (RegOpenKey(hRoot, key, &hSubKey) == ERROR_SUCCESS) - { - RemoveAllSubKeys(hSubKey); - RegCloseKey(hSubKey); - } - RegDeleteKey(hRoot, key); - return TRUE; -} - -//************************************************************************************ -// -// DelRegistryKeys -// - -BOOL DelRegistryKeys() -{ - char* line; - SetupInfo.TmpSection[0] = 0; - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_DELREGKEYS, SetupInfo.TmpSection, sizeof(SetupInfo.TmpSection)); - line = SetupInfo.TmpSection; - while (*line != 0) - { - int len = lstrlen(line); - if (len > 0) - DelRegistryKey(line); - line += len + 1; - } - return TRUE; -} - -//************************************************************************************ -// -// DelFiles -// - -BOOL DelFiles() -{ - char* line; - SetupInfo.TmpSection[0] = 0; - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_DELFILES, SetupInfo.TmpSection, sizeof(SetupInfo.TmpSection)); - line = SetupInfo.TmpSection; - while (*line != 0) - { - int len = lstrlen(line); - if (len > 0) - { - char buff[MAX_PATH]; - lstrcpyn(buff, line, MAX_PATH); - ExpandPath(buff); - DeleteFile(buff); - } - line += len + 1; - } - return TRUE; -} - -//************************************************************************************ -// -// DelEmptyDirs -// - -BOOL DelEmptyDirs() -{ - char* line; - SetupInfo.TmpSection[0] = 0; - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_DELEMPTYDIRS, SetupInfo.TmpSection, sizeof(SetupInfo.TmpSection)); - line = SetupInfo.TmpSection; - while (*line != 0) - { - int len = lstrlen(line); - if (len > 0) - { - char buff[MAX_PATH]; - lstrcpyn(buff, line, MAX_PATH); - ExpandPath(buff); - RemoveDirectoryUtf8Local(buff); - } - line += len + 1; - } - return TRUE; -} - -//************************************************************************************ -// -// CreateRegistryKeys -// - -BOOL CreateRegistryKeys() -{ - char* line; - SetupInfo.TmpSection[0] = 0; - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_CREATEREGKEYS, SetupInfo.TmpSection, sizeof(SetupInfo.TmpSection)); - line = SetupInfo.TmpSection; - while (*line != 0) - { - int len = lstrlen(line); - if (len > 0) - RemoveAddLine(SetupInfo.RemoveRegKeys, line); - line += len + 1; - } - return TRUE; -} - -BOOL AddRegistryValues() -{ - LONG ret; - char* line; - char root[MAX_PATH]; - char key[MAX_PATH]; - char valueName[MAX_PATH]; - char type[100]; - DWORD typeNum; - char value[MAX_PATH]; - char log[1024]; - - SetupInfo.TmpSection[0] = 0; - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_CREATEREGVALUES, SetupInfo.TmpSection, sizeof(SetupInfo.TmpSection)); - line = SetupInfo.TmpSection; - while (*line != 0) - { - HKEY hRoot; - HKEY hKey; - DWORD dwType; - char* begin; - char* end; - - int len = lstrlen(line); - if (len > 0 && line[0] != ';') - { - root[0] = 0; - key[0] = 0; - type[0] = 0; - valueName[0] = 0; - value[0] = 0; - - begin = end = line; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(valueName, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(type, begin, (int)(end - begin + 1)); - typeNum = MyStrToDWORD(type); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(value, begin, (int)(end - begin + 1)); - - if (typeNum == 1 || typeNum == 2 || typeNum == 101 || typeNum == 102) - { - // types below 100 are written to the remove log; those above 100 are not - BOOL writeToRemoveLog = (typeNum < 100); - if (typeNum >= 100) - typeNum -= 100; - - hRoot = GetRootHandle(root); - ret = RegCreateKey(hRoot, key, &hKey); - if (ret != ERROR_SUCCESS) - { - } - - ExpandPath(value); - - if (typeNum == 1) // we support only the types REG_SZ (1) and REG_DWORD (2) - { - dwType = REG_SZ; - ret = RegSetValueEx(hKey, valueName, 0, dwType, value, lstrlen(value)); - } - else - { - DWORD valueNum = MyStrToDWORD(value); - dwType = REG_DWORD; - ret = RegSetValueEx(hKey, valueName, 0, dwType, (const BYTE*)&valueNum, sizeof(valueNum)); - } - if (ret != ERROR_SUCCESS) - { - RegCloseKey(hKey); - return FALSE; - } - if (writeToRemoveLog) - { - wsprintf(log, "%s,%s,%s", root, key, valueName); - RemoveAddLine(SetupInfo.RemoveRegValues, log); - RegCloseKey(hKey); - } - } - } - line += len + 1; - } - - return TRUE; -} - -int GetEXENameLen(const char* buff) -{ - const char* p = buff; - while (*p != 0 && *p != ',') - p++; - return (int)(p - buff); -} - -BOOL IsWow64() -{ - typedef BOOL(WINAPI * LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); - LPFN_ISWOW64PROCESS fnIsWow64Process; - BOOL bIsWow64 = FALSE; - //IsWow64Process is not available on all supported versions of Windows. - //Use GetModuleHandle to get a handle to the DLL that contains the function - //and GetProcAddress to get a pointer to the function if available. - fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process"); - if (NULL != fnIsWow64Process) - { - if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) - { - //handle error - } - } - return bIsWow64; -} - -void AddWERLocalDump(const char* exeName) -{ - // If an x86 application crashes on x64 Windows, WER uses entries from the x64 registry. - // The HKEY_LOCAL_MACHINE\SOFTWARE key is subject to the registry redirector, so the x86 Setup - // sees the x86 view, while the x64 Setup sees the x64 view. From the x86 Setup.exe we need to - // write to the x64 branch of the registry, which can be achieved using the special - // KEY_WOW64_64KEY flag, see MSDN: - // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129%28v=vs.85%29.aspx - // Note that bypassing the redirector also applies to remove.c! - HKEY hKey; - DWORD dwDisposition; - DWORD taskscapeRefCount = 0; - REGSAM samDesired = 0; - if (IsWow64()) - samDesired = KEY_WOW64_64KEY; - RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired | KEY_READ | KEY_WRITE, NULL, &hKey, NULL); - if (hKey != NULL) - { - HKEY hExeKey; - // open or create the key named after the EXE - if (RegCreateKeyEx(hKey, exeName, 0, NULL, REG_OPTION_NON_VOLATILE, samDesired | KEY_READ | KEY_WRITE, NULL, &hExeKey, &dwDisposition) == ERROR_SUCCESS) - { - DWORD dwType; - DWORD dumpCount; - DWORD dumpType; - DWORD customDumpFlags; - const char* dumpFolder = "%LOCALAPPDATA%\\Open Salamander"; - // if the key already existed, read the reference count - if (dwDisposition == REG_OPENED_EXISTING_KEY) - { - DWORD size = sizeof(taskscapeRefCount); - dwType = REG_DWORD; - if (RegQueryValueEx(hExeKey, "TaskscapeLtdRefCount", 0, &dwType, (BYTE*)&taskscapeRefCount, &size) != ERROR_SUCCESS || dwType != REG_DWORD) - taskscapeRefCount = 0; - } - taskscapeRefCount++; - - dwType = REG_DWORD; - RegSetValueEx(hExeKey, "TaskscapeLtdRefCount", 0, dwType, (const BYTE*)&taskscapeRefCount, sizeof(taskscapeRefCount)); - dumpCount = 50; - RegSetValueEx(hExeKey, "DumpCount", 0, dwType, (const BYTE*)&dumpCount, sizeof(dumpCount)); - dumpType = 0; // custom dump type - RegSetValueEx(hExeKey, "DumpType", 0, dwType, (const BYTE*)&dumpType, sizeof(dumpType)); - customDumpFlags = 0x21921; // MINIDUMP_TYPE flags - RegSetValueEx(hExeKey, "CustomDumpFlags", 0, dwType, (const BYTE*)&customDumpFlags, sizeof(customDumpFlags)); - dwType = REG_EXPAND_SZ; - RegSetValueEx(hExeKey, "DumpFolder", 0, dwType, (const BYTE*)dumpFolder, (DWORD)lstrlen(dumpFolder)); - RegCloseKey(hExeKey); - } - RegCloseKey(hKey); - } -} - -void AddWERLocalDumps() -{ - // WER Local Dumps are supported starting with Windows Vista, see - // http://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx - // x64 Salamander has an x64 installer/uninstaller, so it will write to the correct keys - char exeName[MAX_PATH]; - const char* names = SetupInfo.WERLocalDumps; - while (*names != 0) - { - int exeNameLen = GetEXENameLen(names); - if (exeNameLen > 0 && exeNameLen < MAX_PATH - 1) - { - lstrcpyn(exeName, names, exeNameLen + 1); - AddWERLocalDump(exeName); - } - names += exeNameLen; - if (*names == ',') - names++; - } -} - -#define VALUE_LAST_DIRECTORY "LastDirectory" - -// saves the directory where Salamander was installed for the next installation -BOOL SaveLastDirectory() -{ - char root[MAX_PATH]; - char key[MAX_PATH]; - char value[MAX_PATH]; - HKEY hRoot; - HKEY hKey; - char* begin; - char* end; - DWORD dwType; - LONG ret; - - if (SetupInfo.LastDirectories[0] == 0) - return TRUE; - - root[0] = 0; - key[0] = 0; - - begin = end = SetupInfo.LastDirectories; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - hRoot = GetRootHandle(root); - ret = RegCreateKey(hRoot, key, &hKey); - if (ret == ERROR_SUCCESS) - { - lstrcpy(value, SetupInfo.DefaultDirectory); - - dwType = REG_SZ; // we support only type 1 - ret = RegSetValueEx(hKey, VALUE_LAST_DIRECTORY, 0, dwType, value, lstrlen(value)); - if (ret != ERROR_SUCCESS) - { - RegCloseKey(hKey); - return FALSE; - } - RegCloseKey(hKey); - } - return TRUE; -} - -// retrieves LastDir from the registry -BOOL LoadLastDirectory() -{ - char root[MAX_PATH]; - char key[MAX_PATH]; - char* keyLastComponent; - char value[MAX_PATH]; - HKEY hRoot; - HKEY hKey; - char* begin; - char* end; - DWORD dwType; - DWORD dwDataSize; - LONG ret; - BOOL exit; - - if (SetupInfo.LastDirectories[0] == 0) - return FALSE; - - root[0] = 0; - key[0] = 0; - value[0] = 0; - - // extract the root - begin = end = SetupInfo.LastDirectories; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - // extract the path to the key valid for the currently installed version - begin = end; - keyLastComponent = NULL; // will point past the last backslash, where we will insert older candidates from the list if the current one fails - while (*end != 0 && *end != ',') - { - if (*end == '\\') - keyLastComponent = key + (end - begin + 1); - end++; - } - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - // if we did not find the last component, something is wrong and it's time to bail out - if (keyLastComponent == NULL) - return FALSE; - - hRoot = GetRootHandle(root); - - exit = FALSE; - do - { - // open the key - ret = RegOpenKeyEx(hRoot, key, 0, KEY_QUERY_VALUE, &hKey); - if (ret == ERROR_SUCCESS) - { - // and try to read the REG_SZ string "LastDirectory" - dwType = REG_SZ; // we support only type 1 - dwDataSize = MAX_PATH; - ret = RegQueryValueEx(hKey, VALUE_LAST_DIRECTORY, 0, &dwType, value, &dwDataSize); - RegCloseKey(hKey); - if (ret == ERROR_SUCCESS && dwType == REG_SZ && value[0] != 0) - { - // we have a candidate directory we could use - // verify whether it meets additional conditions - if (ContainsPathUpgradableVersion(value)) - { - lstrcpy(SetupInfo.DefaultDirectory, value); - return TRUE; - } - } - } - - // we did not find a suitable directory for the current version, so try - // older versions according to the list - begin = end; - while (*end != 0 && *end != ',') - end++; - if (*begin != 0) - { - lstrcpyn(keyLastComponent, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - } - else - exit = TRUE; - } while (!exit); - - return FALSE; -} - -const char* REMOVE_OPTIONS = "[Options]\r\n"; -const char* REMOVE_APPNAME = "UninstallApplication="; -const char* REMOVE_WERLOCALDUMPS = "UninstallWERLocalDumps="; -const char* REMOVE_RUNQUIET = "RunProgramQuiet="; -const char* REMOVE_CHECKRUNNING = "CheckRunningApps="; -const char* REMOVE_UNPINFROMTASKBAR = "[UnpinFromTaskbar]\r\n"; -const char* REMOVE_DELREGKEYS = "[DelRegKeys]\r\n"; -const char* REMOVE_DELREGVALS = "[DelRegValues]\r\n"; -const char* REMOVE_DELFILES = "[DelFiles]\r\n"; -const char* REMOVE_DELDIRS = "[DelDirs]\r\n"; -const char* REMOVE_OPTIONS2 = "Options"; -const char* REMOVE_DELREGKEYS2 = "DelRegKeys"; -const char* REMOVE_DELREGVALS2 = "DelRegValues"; -const char* REMOVE_DELFILES2 = "DelFiles"; -const char* REMOVE_DELDIRS2 = "DelDirs"; -const char* REMOVE_DELSHELLEXTS = "[DelShellExts]\r\n"; -const char* REMOVE_NEXTLINE = "\r\n"; - -// writes a list of strings separated by zeros and terminated with two zeros -// to a file; lines end with \r\n -void WriteList(HANDLE hFile, const char* list, BOOL expand) -{ - char buff[5000]; - DWORD written; - const char* p = list; - lstrcpy(buff, "\r\n"); - while (*p != 0) - { - lstrcpyn(buff, p, 4990); - if (expand) - ExpandPath(buff); - lstrcat(buff, "\r\n"); - WriteFile(hFile, buff, lstrlen(buff), &written, NULL); - p += lstrlen(p) + 1; - } -} - -BOOL SaveRemoveLog() -{ - HANDLE hFile; - char buff[300]; - DWORD written; - if (SetupInfo.SaveRemoveLog[0] == 0) - return TRUE; - - hFile = CreateFile(SetupInfo.SaveRemoveLog, GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL); - if (hFile == INVALID_HANDLE_VALUE) - { - if (!SetupInfo.Silent) - { - wsprintf(buff, LoadStr(IDS_ERRORCREATELOG), SetupInfo.SaveRemoveLog); - MessageBox(HWizardDialog, buff, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - } - return FALSE; - } - - WriteFile(hFile, REMOVE_OPTIONS, - lstrlen(REMOVE_OPTIONS), &written, NULL); - - if (SetupInfo.LoadOldRemoveLog) - { - char* p = SetupInfo.OldRemoveOptions; - lstrcpy(buff, "\r\n"); - while (*p != 0) - { - int len = lstrlen(p); - WriteFile(hFile, p, len, &written, NULL); - WriteFile(hFile, buff, 2, &written, NULL); - p += len + 1; - } - } - else - { - lstrcpy(buff, REMOVE_APPNAME); - lstrcat(buff, SetupInfo.ApplicationNameVer); - lstrcat(buff, "\r\n"); - WriteFile(hFile, buff, lstrlen(buff), &written, NULL); - if (SetupInfo.UnistallRunProgramQuietPath[0] != 0) - { - lstrcpy(buff, REMOVE_RUNQUIET); - lstrcat(buff, SetupInfo.UnistallRunProgramQuietPath); - lstrcat(buff, "\r\n"); - WriteFile(hFile, buff, lstrlen(buff), &written, NULL); - } - if (SetupInfo.CheckRunningApps[0] != 0) - { - lstrcpy(buff, REMOVE_CHECKRUNNING); - lstrcat(buff, SetupInfo.CheckRunningApps); - lstrcat(buff, "\r\n"); - WriteFile(hFile, buff, lstrlen(buff), &written, NULL); - } - if (SetupInfo.WERLocalDumps[0] != 0) - { - lstrcpy(buff, REMOVE_WERLOCALDUMPS); - lstrcat(buff, SetupInfo.WERLocalDumps); - lstrcat(buff, "\r\n"); - WriteFile(hFile, buff, lstrlen(buff), &written, NULL); - } - } - - WriteFile(hFile, REMOVE_NEXTLINE, - lstrlen(REMOVE_NEXTLINE), &written, NULL); - - RemoveAddLine(SetupInfo.RemoveFiles, SetupInfo.SaveRemoveLog); - - // Delete Files - if (SetupInfo.UnpinFromTaskbar[0] != 0) - { - WriteFile(hFile, REMOVE_UNPINFROMTASKBAR, - lstrlen(REMOVE_UNPINFROMTASKBAR), &written, NULL); - WriteList(hFile, SetupInfo.UnpinFromTaskbar, FALSE); - WriteFile(hFile, REMOVE_NEXTLINE, - lstrlen(REMOVE_NEXTLINE), &written, NULL); - } - - // Delete Files - if (SetupInfo.RemoveFiles[0] != 0) - { - WriteFile(hFile, REMOVE_DELFILES, - lstrlen(REMOVE_DELFILES), &written, NULL); - WriteList(hFile, SetupInfo.RemoveFiles, FALSE); - WriteFile(hFile, REMOVE_NEXTLINE, - lstrlen(REMOVE_NEXTLINE), &written, NULL); - } - - // Delete Dirs - if (SetupInfo.RemoveDirs[0] != 0) - { - WriteFile(hFile, REMOVE_DELDIRS, - lstrlen(REMOVE_DELDIRS), &written, NULL); - WriteList(hFile, SetupInfo.RemoveDirs, FALSE); - WriteFile(hFile, REMOVE_NEXTLINE, - lstrlen(REMOVE_NEXTLINE), &written, NULL); - } - - // Delete Reg Values - if (SetupInfo.RemoveRegValues[0] != 0) - { - WriteFile(hFile, REMOVE_DELREGVALS, - lstrlen(REMOVE_DELREGVALS), &written, NULL); - WriteList(hFile, SetupInfo.RemoveRegValues, FALSE); - WriteFile(hFile, REMOVE_NEXTLINE, - lstrlen(REMOVE_NEXTLINE), &written, NULL); - } - - // Delete Reg Keys - if (SetupInfo.RemoveRegKeys[0] != 0) - { - WriteFile(hFile, REMOVE_DELREGKEYS, - lstrlen(REMOVE_DELREGKEYS), &written, NULL); - WriteList(hFile, SetupInfo.RemoveRegKeys, FALSE); - WriteFile(hFile, REMOVE_NEXTLINE, - lstrlen(REMOVE_NEXTLINE), &written, NULL); - } - - // Delete Shell Extensions - if (SetupInfo.RemoveShellExts[0] != 0) - { - WriteFile(hFile, REMOVE_DELSHELLEXTS, - lstrlen(REMOVE_DELSHELLEXTS), &written, NULL); - WriteList(hFile, SetupInfo.RemoveShellExts, TRUE); - WriteFile(hFile, REMOVE_NEXTLINE, - lstrlen(REMOVE_NEXTLINE), &written, NULL); - } - - CloseHandle(hFile); - return TRUE; -} - -BOOL LoadRemoveLog() -{ - HANDLE hFile; - char removeLog[100000]; - DWORD read; - if (SetupInfo.SaveRemoveLog[0] == 0) - return TRUE; - - hFile = CreateFile(SetupInfo.SaveRemoveLog, GENERIC_READ, 0, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; - - if (!ReadFile(hFile, removeLog, 100000, &read, NULL)) - { - CloseHandle(hFile); - return FALSE; - } - CloseHandle(hFile); - - if (read > 99999) - read = 99999; - removeLog[read] = 0; - - MyGetPrivateProfileSection(removeLog, REMOVE_OPTIONS2, SetupInfo.OldRemoveOptions, sizeof(SetupInfo.OldRemoveOptions)); - - // load the lists slated for removal - MyGetPrivateProfileSection(removeLog, REMOVE_UNPINFROMTASKBAR, SetupInfo.UnpinFromTaskbar, sizeof(SetupInfo.UnpinFromTaskbar)); - MyGetPrivateProfileSection(removeLog, REMOVE_DELFILES2, SetupInfo.RemoveFiles, sizeof(SetupInfo.RemoveFiles)); - MyGetPrivateProfileSection(removeLog, REMOVE_DELDIRS2, SetupInfo.RemoveDirs, sizeof(SetupInfo.RemoveDirs)); - MyGetPrivateProfileSection(removeLog, REMOVE_DELREGVALS2, SetupInfo.RemoveRegValues, sizeof(SetupInfo.RemoveRegValues)); - MyGetPrivateProfileSection(removeLog, REMOVE_DELREGKEYS2, SetupInfo.RemoveRegKeys, sizeof(SetupInfo.RemoveRegKeys)); - MyGetPrivateProfileSection(removeLog, REMOVE_DELSHELLEXTS, SetupInfo.RemoveShellExts, sizeof(SetupInfo.RemoveShellExts)); - - return TRUE; -} - -BOOL DoGetRegistryVarSectionLine(char* line) -{ - char pathVar[MAX_PATH]; - char root[MAX_PATH]; - char key[MAX_PATH]; - char valueName[MAX_PATH]; - char value[MAX_PATH]; - char error[1024]; - char* begin; - char* end; - - HKEY hRoot; - HKEY hKey; - DWORD dwType; - DWORD dwDataSize; - LONG ret; - - pathVar[0] = 0; - root[0] = 0; - key[0] = 0; - valueName[0] = 0; - value[0] = 0; - error[0] = 0; - - begin = end = line; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(pathVar, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(valueName, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(error, begin, (int)(end - begin + 1)); - - hRoot = GetRootHandle(root); - ret = RegOpenKeyEx(hRoot, key, 0, KEY_QUERY_VALUE, &hKey); - if (ret == ERROR_SUCCESS) - { - dwType = REG_SZ; // we support only type 1 - dwDataSize = MAX_PATH; - ret = RegQueryValueEx(hKey, valueName, 0, &dwType, value, &dwDataSize); - RegCloseKey(hKey); - if (ret == ERROR_SUCCESS) - { - if (pathVar[1] >= 'a' && pathVar[1] <= 'z') - pathVar[1] = 'A' + pathVar[1] - 'a'; - if (pathVar[0] != '%' || pathVar[1] < 'A' || pathVar[1] > 'Z') - { - if (!SetupInfo.Silent) - MessageBox(NULL, "Syntax error in [GetRegistryVar]", MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - return FALSE; - } - - // remove the trailing backslash if present - if (lstrlen(value) > 1 && value[lstrlen(value) - 1] == '\\') - value[lstrlen(value) - 1] = 0; - - lstrcpyn(SetupInfo.RegPathVal[pathVar[1] - 'A'], value, MAX_PATH); - return TRUE; - } - } - if (!SetupInfo.Silent) - MessageBox(NULL, error, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - return FALSE; -} - -BOOL DoGetRegistryVarSection() -{ - char* line; - - SetupInfo.TmpSection[0] = 0; - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_GETREGVAR, SetupInfo.TmpSection, sizeof(SetupInfo.TmpSection)); - line = SetupInfo.TmpSection; - - while (*line != 0) - { - int len = lstrlen(line); - if (len > 0 && line[0] != ';') - { - if (!DoGetRegistryVarSectionLine(line)) - return FALSE; - } - line += len + 1; - } - return TRUE; -} - -BOOL FindConflictWithAnotherVersion(BOOL* sameOrOlderVersion, BOOL* sameVersion, /*BOOL *sameOrOlderVersionIgnoringBuild, BOOL *sameVersionIgnoringBuild, */ BOOL* foundRemoveLog) -{ - int i; - char src[MAX_PATH]; - char dst[MAX_PATH]; - char* from; - char* to; - - from = SetupInfo.CopyFrom; - to = SetupInfo.CopyTo; - for (i = 0; i < SetupInfo.CopyCount; i++) - { - DWORD flags; - - lstrcpy(src, from); - lstrcpy(dst, to); - - ExpandPath(src); - ExpandPath(dst); - - src[lstrlen(src) + 1] = 0; - dst[lstrlen(dst) + 1] = 0; - - flags = SetupInfo.CopyFlags[i]; - if (flags & COPY_FLAG_TEST_CONFLICT) // should we test the module for the existence of another version? - { - DWORD srcMajor, srcMinor; - DWORD dstMajor, dstMinor; - HINSTANCE hSrc, hDst; - - // try to load both modules - hSrc = LoadLibraryEx(src, NULL, LOAD_LIBRARY_AS_DATAFILE); - hDst = LoadLibraryEx(dst, NULL, LOAD_LIBRARY_AS_DATAFILE); - if (hSrc != NULL && hDst != NULL) - { - if (GetModuleVersion(hSrc, &srcMajor, &srcMinor) && GetModuleVersion(hDst, &dstMajor, &dstMinor)) - { - // including the build WORD - if (sameOrOlderVersion != NULL) - { - *sameOrOlderVersion = (dstMajor == srcMajor && dstMinor == srcMinor) || - (dstMajor < srcMajor) || (dstMajor == srcMajor && dstMinor < srcMinor); - } - if (sameVersion != NULL) - { - *sameVersion = (dstMajor == srcMajor && dstMinor == srcMinor); - } - - /* during the 2.52 beta 2 release we learned that we cannot ignore the build number; - when upgrading from beta 1 the installer reported that an application with the same version was already installed - // ignoring the build WORD - dstMinor &= 0xffff0000; - srcMinor &= 0xffff0000; - if (sameOrOlderVersionIgnoringBuild != NULL) - { - *sameOrOlderVersionIgnoringBuild = (dstMajor == srcMajor && dstMinor == srcMinor) || - (dstMajor < srcMajor) || (dstMajor == srcMajor && dstMinor < srcMinor); - } - if (sameVersionIgnoringBuild != NULL) - { - *sameVersionIgnoringBuild = (dstMajor == srcMajor && dstMinor == srcMinor); - } -*/ - FreeLibrary(hSrc); - FreeLibrary(hDst); - - if (foundRemoveLog != NULL) - { - char removeLog[MAX_PATH]; - DWORD attrs; - lstrcpy(removeLog, SetupInfo.SaveRemoveLog); - ExpandPath(removeLog); - attrs = GetFileAttributesUtf8Local(removeLog); - *foundRemoveLog = (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) == 0); - } - - return TRUE; - } - } - if (hSrc != NULL) - FreeLibrary(hSrc); - if (hDst != NULL) - FreeLibrary(hDst); - } - - from += lstrlen(from) + 1; - to += lstrlen(to) + 1; - } - return FALSE; -} - -// checks the given path for "salamand.exe" and "remove.rlg" -- two files required for a potential upgrade -BOOL ContainsPathUpgradableVersion(const char* path) -{ - char backupDefaultDirectory[MAX_PATH]; - BOOL foundAnotherEXEVersion; - BOOL foundRemoveLog; - BOOL sameOrOlderVersion; - - // the path must exist - DWORD attrs = GetFileAttributesUtf8Local(path); - if (attrs == INVALID_FILE_ATTRIBUTES || (attrs & FILE_ATTRIBUTE_DIRECTORY) == 0) - return FALSE; - - // back up the global value - lstrcpy(backupDefaultDirectory, SetupInfo.DefaultDirectory); - // set the global so that paths expand correctly - lstrcpy(SetupInfo.DefaultDirectory, path); - - // verify whether the directory contains an older or identical EXE version - foundAnotherEXEVersion = FindConflictWithAnotherVersion(&sameOrOlderVersion, NULL, &foundRemoveLog); - - // restore from the backup - lstrcpy(SetupInfo.DefaultDirectory, backupDefaultDirectory); - - if (foundAnotherEXEVersion && sameOrOlderVersion && foundRemoveLog) - return TRUE; - - return FALSE; -} - -BOOL RefreshDesktop(BOOL sleep) -{ - ITEMIDLIST root = {0}; - SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, &root, 0); - if (sleep) - Sleep(500); // give the system some time - return TRUE; -} - -BOOL DoInstallation() -{ - int progress = 0; - int i; - char src[MAX_PATH]; - char dst[MAX_PATH]; - char* from; - char* to; - int options; - BOOL overwriteAll; - BOOL skipAll; - BOOL skipAllCreate; - - SetupInfo.OldRemoveOptions[0] = 0; - SetupInfo.OldRemoveOptions[1] = 0; - SetupInfo.UnpinFromTaskbar[0] = 0; - SetupInfo.UnpinFromTaskbar[1] = 0; - SetupInfo.RemoveFiles[0] = 0; - SetupInfo.RemoveFiles[1] = 0; - SetupInfo.RemoveDirs[0] = 0; - SetupInfo.RemoveDirs[1] = 0; - SetupInfo.RemoveRegValues[0] = 0; - SetupInfo.RemoveRegValues[1] = 0; - SetupInfo.RemoveRegKeys[0] = 0; - SetupInfo.RemoveRegKeys[1] = 0; - - ExpandPath(SetupInfo.SaveRemoveLog); - if (SetupInfo.LoadOldRemoveLog) - LoadRemoveLog(); - - SetProgressMax(SetupInfo.CopyCount - 1 + 11); - SetProgressPos(progress++); - - if (!CreateDirs()) // 1 - return FALSE; - SetProgressPos(progress++); - - from = SetupInfo.CopyFrom; - to = SetupInfo.CopyTo; - - SetFromTo("", ""); - - overwriteAll = FALSE; - skipAll = FALSE; - skipAllCreate = FALSE; - - for (i = 0; i < SetupInfo.CopyCount; i++) - { - char dir[MAX_PATH]; - char* iter; - DWORD flags; - - lstrcpy(src, from); - lstrcpy(dst, to); - - ExpandPath(src); - ExpandPath(dst); - - src[lstrlen(src) + 1] = 0; - dst[lstrlen(dst) + 1] = 0; - - SetFromTo(src, dst); - if (!SetupInfo.Silent) - UpdateWindow(HProgressDialog); - - lstrcpy(dir, dst); - iter = (char*)MyRStrChr(dir, '\\'); - if (iter != NULL) - { - *iter = 0; - if (!CheckAndCreateDirectory(dir)) - return FALSE; - } - - flags = SetupInfo.CopyFlags[i]; - if (!MyCopyFile(src, dst, overwriteAll, skipAll, skipAllCreate, &options, flags)) - { - return FALSE; - } - - if (options == COPYFILEOPTIONS_CANCEL) - return FALSE; - - if (options == COPYFILEOPTIONS_SKIPALL) - skipAll = TRUE; - - if (options == COPYFILEOPTIONS_OVERWRITEALL) - overwriteAll = TRUE; - - if (options == COPYFILEOPTIONS_SKIPALL_CREATE) - skipAllCreate = TRUE; - - if (!(flags & COPY_FLAG_NOREMOVE) && - (options == COPYFILEOPTIONS_SUCCESS || options == COPYFILEOPTIONS_OVERWRITE || - options == COPYFILEOPTIONS_OVERWRITEALL)) - RemoveAddLine(SetupInfo.RemoveFiles, dst); - - from += lstrlen(from) + 1; - to += lstrlen(to) + 1; - - SetProgressPos(progress++); - Sleep(0); - } - - SetProgressPos(progress++); - - SetFromTo("", ""); - DelRegistryValues(); // 3 - SetProgressPos(progress++); - DelRegistryKeys(); // 4 - SetProgressPos(progress++); - DelFiles(); // 5 - SetProgressPos(progress++); - DelEmptyDirs(); // 6 - SetProgressPos(progress++); - CreateShortcuts(); // 7 - SetProgressPos(progress++); - CreateRegistryKeys(); // 8 - SetProgressPos(progress++); - AddRegistryValues(); // 9 - AddWERLocalDumps(); - SetProgressPos(progress++); - // SaveLastDirectory(); // 10 // we will perform this after starting the installation - // SetProgressPos(progress++); - ExpandPath(SetupInfo.UnistallRunProgramQuietPath); - - MyGetPrivateProfileSection(SetupInfo.InfFile, INF_DELSHELLEXTS, SetupInfo.RemoveShellExts, sizeof(SetupInfo.RemoveShellExts)); - - SaveRemoveLog(); // 10 - - if (SetupInfo.IncrementFileContentSrc[0] != 0 && SetupInfo.IncrementFileContentDst[0] != 0) - IncrementFileContent(); - - SetProgressPos(progress++); - - // under W2K it happened that after installing Sal2.51 the Sal2.5 icon remained on the desktop and disappeared only after - // manually refreshing (F5) the desktop; the link itself was already deleted, only the desktop kept showing the icon - RefreshDesktop(FALSE); - - return TRUE; -} - diff --git a/src/setup/infinst.c b/src/setup/infinst.c deleted file mode 100644 index ab609f96..00000000 --- a/src/setup/infinst.c +++ /dev/null @@ -1,760 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "precomp.h" -#include - -#include "infinst.h" -#include "resource.h" - -//************************************************************************************ -// -// Globals -// - -const char* MAINWINDOW_CLASS = "TaskscapeLtdInstallMW"; -char MAINWINDOW_TITLE[100] = {0}; - -INSTALLINFO SetupInfo = {0}; // a structure containing the review information -HINSTANCE HInstance = NULL; - -BOOL SfxDirectoriesValid = FALSE; -char SfxDirectories[7][MAX_PATH]; - -HWND SfxDlg = NULL; // SFX7ZIP window that launched this setup.exe (before setup.exe exits we show and activate it so the installed readme and Salam can be launched from it) -BOOL RunBySfx = FALSE; // TRUE if setup.exe was started with the /runbysfx parameter - -BYTE LowerCase[256]; - -int StrICmp(const char* s1, const char* s2) -{ - int res; - while (1) - { - res = (unsigned)LowerCase[*s1] - (unsigned)LowerCase[*s2++]; - if (res != 0) - return (res < 0) ? -1 : 1; // < a > - if (*s1++ == 0) - return 0; // == - } -} - -//************************************************************************************ -// -// LoadStr -// - -char* LoadStr(int resID) -{ - int size; - char* ret; - static char buffer[5000]; // buffer for many strings - static char* act = buffer; - - // HANDLES(EnterCriticalSection(&__StrCriticalSection.cs)); - - if (5000 - (act - buffer) < 200) - act = buffer; - size = LoadString(HInstance, resID, act, 5000 - (int)(act - buffer)); - if (size != 0 || GetLastError() == NO_ERROR) - { - ret = act; - act += size + 1; - } - else - { - ret = "ERROR LOADING STRING"; - } - - // HANDLES(LeaveCriticalSection(&__StrCriticalSection.cs)); - - return ret; -} - -//************************************************************************************ -// -// CenterWindow -// - -void CenterWindow(HWND hWindow) -{ - RECT masterRect; - RECT slaveRect; - int x, y, w, h; - int mw, mh; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &masterRect, 0); - - GetWindowRect(hWindow, &slaveRect); - w = slaveRect.right - slaveRect.left; - h = slaveRect.bottom - slaveRect.top; - mw = masterRect.right - masterRect.left; - mh = masterRect.bottom - masterRect.top; - x = masterRect.left + (mw - w) / 2; - y = masterRect.top + (mh - h) / 2; - SetWindowPos(hWindow, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); -} - -//************************************************************************************ -// -// InsertProgramName -// -// replaces %s in str with the name of the installed application -// - -void InsertProgramName(char* str, BOOL version) -{ - char buff[1024]; - if (version) - wsprintf(buff, str, SetupInfo.ApplicationNameVer); - else - wsprintf(buff, str, SetupInfo.ApplicationName); - lstrcpy(str, buff); -} - -//************************************************************************************ -// -// InsertAppName -// - -void InsertAppName(HWND hDlg, int resID, BOOL version) -{ - char buff[1024]; - HWND hText = GetDlgItem(hDlg, resID); - GetWindowText(hText, buff, 1024); - InsertProgramName(buff, version); - SetWindowText(hText, buff); -} - -//************************************************************************************ -// -// LoadLTextFile -// - -BOOL LoadTextFile(const char* fileName, char* buff, int buffMax) -{ - HANDLE hFile; - DWORD read; - - hFile = CreateFile(fileName, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; - - if (!ReadFile(hFile, - buff, - buffMax, - &read, - NULL)) - { - CloseHandle(hFile); - return FALSE; - } - - CloseHandle(hFile); - return TRUE; -} - -// **************************************************************************** -// EnableExceptionsOn64 -// - -// We want to be notified about SEH exceptions even on x64 Windows 7 SP1 and later -// http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/ -// http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages -// http://support.microsoft.com/kb/976038 -void EnableExceptionsOn64() -{ - typedef BOOL(WINAPI * FSetProcessUserModeExceptionPolicy)(DWORD dwFlags); - typedef BOOL(WINAPI * FGetProcessUserModeExceptionPolicy)(LPDWORD dwFlags); - typedef BOOL(WINAPI * FIsWow64Process)(HANDLE, PBOOL); -#define PROCESS_CALLBACK_FILTER_ENABLED 0x1 - - HINSTANCE hDLL = LoadLibrary("KERNEL32.DLL"); - if (hDLL != NULL) - { - FIsWow64Process isWow64 = (FIsWow64Process)GetProcAddress(hDLL, "IsWow64Process"); - FSetProcessUserModeExceptionPolicy set = (FSetProcessUserModeExceptionPolicy)GetProcAddress(hDLL, "SetProcessUserModeExceptionPolicy"); - FGetProcessUserModeExceptionPolicy get = (FGetProcessUserModeExceptionPolicy)GetProcAddress(hDLL, "GetProcessUserModeExceptionPolicy"); - if (isWow64 != NULL && set != NULL && get != NULL) - { - BOOL bIsWow64; - if (isWow64(GetCurrentProcess(), &bIsWow64) && bIsWow64) - { - DWORD dwFlags; - if (get(&dwFlags)) - set(dwFlags & ~PROCESS_CALLBACK_FILTER_ENABLED); - } - } - FreeLibrary(hDLL); - } -} - -//************************************************************************************ -// -// WinMain -// - -char* strrchr(const char* string, int c) -{ - char* iter; - int len; - if (string == NULL) - return NULL; - len = lstrlen(string); - iter = (char*)string + len - 1; - while (iter >= string) - { - if (*iter == c) - return iter; - iter--; - } - return NULL; -} - -void* mini_memcpy(void* out, const void* in, int len); // defined in the remove part of the code - -BOOL GetStringFromDLL(const char* dllName, int resID, char* buff, int buffSize) -{ - BOOL ret = FALSE; - HINSTANCE hDLL = LoadLibraryEx(dllName, NULL, LOAD_LIBRARY_AS_DATAFILE); - if (hDLL != NULL) - { - if (LoadString(hDLL, resID, buff, buffSize)) - ret = TRUE; - FreeLibrary(hDLL); - } - return ret; -} - -void ExpandPath(char* path) -{ - char buff[MAX_PATH]; - char* src; - char* dst; - const char* mui = NULL; - src = path; - dst = buff; - *dst = 0; - while (*src != 0) - { - char srcVal = *(src + 1); - if (*src == '%' && - (srcVal == '%' || - srcVal == '@' && mui == NULL || // only one MUI marker per line, ending with the end of the line - srcVal >= '0' && srcVal <= '9' || - srcVal >= 'A' && srcVal <= 'Z' || - srcVal >= 'a' && srcVal <= 'z')) - { - int len; - char* p = NULL; - if (srcVal == '%') - { - p = "%"; // %% -> % - } - else if (srcVal == '@') - { - p = "@"; - mui = dst; // store the MUI marker for potential final expansion - } - else if (srcVal >= '0' && srcVal <= '9') - { - switch (srcVal) - { - case '0': - p = ModulePath; - break; - case '1': - p = SetupInfo.DefaultDirectory; - break; - case '2': - p = WindowsDirectory; - break; - case '3': - p = SystemDirectory; - break; - case '4': - p = ProgramFilesDirectory; - break; - case '5': - p = DesktopDirectory; - break; - case '6': - p = StartMenuDirectory; - break; - case '7': - p = StartMenuProgramDirectory; - break; - case '8': - p = QuickLaunchDirectory; - break; - } - } - else - { - if (srcVal >= 'a' && srcVal <= 'z') - srcVal = 'A' + srcVal - 'a'; - p = SetupInfo.RegPathVal[srcVal - 'A']; - } - - len = 0; - if (p != NULL) - { - len = lstrlen(p); - mini_memcpy(dst, p, len); - } - src += 2; - dst += len; - } - else - { - *dst = *src; - dst++; - src++; - } - } - *dst = 0; - lstrcpy(path, buff); -} - -// **************************************************************************** -// -// GetCmdLine - extract parameters from the command line -// -// buf + size - buffer for the parameters -// argv - array of pointers that will be filled with the parameters -// argCount - on input the number of elements in argv; on output contains the number of parameters -// cmdLine - command-line parameters (without the .exe file name - from WinMain) - -BOOL GetCmdLine(char* buf, int size, char* argv[], int* argCount, const char* cmdLine) -{ - int space = *argCount; - char* c = buf; - char* end = buf + size; - const char* s = cmdLine; - char term; - *argCount = 0; - - while (*s != 0) - { - if (*s == '"') // opening '"' - { - if (*++s == 0) - break; - term = '"'; - } - else - term = ' '; - - if (*argCount < space && c < end) - argv[(*argCount)++] = c; - else - return c < end; // failure only if the buffer is too small - - while (1) - { - if (*s == term || *s == 0) - { - if (*s == 0 || term != '"' || *++s != '"') // unless this is the escaped "" -> " sequence - { - if (*s != 0) - s++; - while (*s != 0 && *s == ' ') - s++; - if (c < end) - { - *c++ = 0; - break; - } - else - return FALSE; - } - } - if (c < end) - *c++ = *s++; - else - return FALSE; - } - } - return TRUE; -} - -BOOL LoadSfxDirectories(HANDLE* fileOut, BOOL openAndPrepareForWrite) -{ - char name[MAX_PATH]; - HANDLE file; - - if (!openAndPrepareForWrite) - SfxDirectoriesValid = FALSE; - - GetModuleFileName(NULL, name, MAX_PATH); - lstrcpy(strrchr(name, '\\'), "\\params.txt"); - - file = CreateFile(name, GENERIC_READ | (openAndPrepareForWrite ? GENERIC_WRITE : 0), - 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (file != INVALID_HANDLE_VALUE) - { - DWORD sizeLo, sizeHi; - if (fileOut != NULL) - *fileOut = file; - sizeLo = GetFileSize(file, &sizeHi); - if ((sizeLo != INVALID_FILE_SIZE || GetLastError() == NO_ERROR) && - sizeHi == 0 && sizeLo <= 3000) - { - char buf[3001]; - DWORD read; - if (ReadFile(file, buf, sizeLo, &read, NULL) && read == sizeLo) - { - int index; - char* end; - char* line; - char* s; - - index = 0; - end = buf + read; - line = buf; - s = line; - while (s < end) - { - while (s < end && *s != '\r' && *s != '\n') - s++; - *s++ = 0; // s == end is still a valid position - - if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, line, -1, "end-of-params", -1) == CSTR_EQUAL && - index == 7) - { - if (openAndPrepareForWrite) - { - SetFilePointer(file, (int)((s - 1) - buf), NULL, FILE_BEGIN); - SetEndOfFile(file); - return TRUE; - } - SfxDirectoriesValid = TRUE; - break; - } - if (index < 7 && !openAndPrepareForWrite) - lstrcpyn(SfxDirectories[index], line, MAX_PATH); - index++; - - while (s < end && (*s == '\r' || *s == '\n')) - s++; - line = s; - } - } - } - CloseHandle(file); - } - return FALSE; -} - -BOOL StoreExecuteInfo(const char* cmdLineViewer, const char* cmdLineProgram, BOOL execViewer, BOOL execProgram) -{ - HANDLE file; - BOOL ret = FALSE; - if (LoadSfxDirectories(&file, TRUE)) - { - DWORD written; - if (WriteFile(file, "\r\n", 2, &written, NULL) && written == 2 && - WriteFile(file, cmdLineViewer, lstrlen(cmdLineViewer), &written, NULL) && written == (DWORD)lstrlen(cmdLineViewer) && - WriteFile(file, "\r\n", 2, &written, NULL) && written == 2 && - WriteFile(file, cmdLineProgram, lstrlen(cmdLineProgram), &written, NULL) && written == (DWORD)lstrlen(cmdLineProgram) && - WriteFile(file, "\r\n", 2, &written, NULL) && written == 2) - { - if (!execViewer || - WriteFile(file, "exec-viewer", sizeof("exec-viewer") - 1, &written, NULL) && written == sizeof("exec-viewer") - 1 && - WriteFile(file, "\r\n", 2, &written, NULL) && written == 2) - { - if (!execProgram || - WriteFile(file, "exec-salamander", sizeof("exec-salamander") - 1, &written, NULL) && written == sizeof("exec-salamander") - 1 && - WriteFile(file, "\r\n", 2, &written, NULL) && written == 2) - { - ret = TRUE; - } - } - } - CloseHandle(file); - } - return ret; -} - -DWORD Hex2DWORD(const char* s) -{ - DWORD ret = 0; - if (*s == '0' && *(s + 1) == 'x') - { - s += 2; - while (*s != 0) - { - if (*s >= '0' && *s <= '9') - ret = ret * 16 + (*s++ - '0'); - else if (*s >= 'a' && *s <= 'f') - ret = ret * 16 + 10 + (*s++ - 'a'); - else if (*s >= 'A' && *s <= 'F') - ret = ret * 16 + 10 + (*s++ - 'A'); - else - break; // not hexadecimal, stop - } - } - return ret; -} - -BOOL GetCmdLineOptions(const char* cmdLine) -{ - char buf[MAX_PATH]; - char* argv[30]; - int p = 30; // number of elements in the argv array - BOOL ret = TRUE; - if (GetCmdLine(buf, MAX_PATH, argv, &p, cmdLine)) - { - int i; - for (i = 0; i < p; i++) - { - if ((StrICmp(argv[i], "-runbysfx") == 0 || StrICmp(argv[i], "/runbysfx") == 0)) // setup.exe started from the non-elevated sfx7zip.exe; take paths from the non-elevated process and optionally have it open the Readme and launch Salamander - { - if (i + 1 < p) - { - RunBySfx = TRUE; - SfxDlg = (HWND)(DWORD_PTR)Hex2DWORD(argv[i + 1]); - LoadSfxDirectories(NULL, FALSE); - i++; - continue; - } - // otherwise it's an error - } - - if (StrICmp(argv[i], "-s") == 0 || StrICmp(argv[i], "/s") == 0) // silent mode - { - SetupInfo.Silent = TRUE; - continue; - } - - if (StrICmp(argv[i], "-d") == 0 || StrICmp(argv[i], "/d") == 0) // destination - { - if (i + 1 < p) - { - lstrcpyn(CmdLineDestination, argv[i + 1], MAX_PATH); - i++; - continue; - } - // otherwise it's an error - } - - if (StrICmp(argv[i], "-id") == 0 || StrICmp(argv[i], "/id") == 0) // desktop icon - { - if (i + 1 < p && StrICmp(argv[i + 1], "y") == 0 || StrICmp(argv[i + 1], "n") == 0) - { - SetupInfo.ShortcutInDesktop = (StrICmp(argv[i + 1], "y") == 0); - i++; - continue; - } - // otherwise it's an error - } - - if (StrICmp(argv[i], "-is") == 0 || StrICmp(argv[i], "/is") == 0) // start menu icon - { - if (i + 1 < p && StrICmp(argv[i + 1], "y") == 0 || StrICmp(argv[i + 1], "n") == 0) - { - SetupInfo.ShortcutInStartMenu = (StrICmp(argv[i + 1], "y") == 0); - i++; - continue; - } - // otherwise it's an error - } - - //if (StrICmp(argv[i], "-it") == 0 || StrICmp(argv[i], "/it") == 0) // pin to taskbar - //{ - // if (i + 1 < p && StrICmp(argv[i + 1], "y") == 0 || StrICmp(argv[i + 1], "n") == 0) - // { - // SetupInfo.PinToTaskbar = (StrICmp(argv[i + 1], "y") == 0); - // i++; - // continue; - // } - // // otherwise it's an error - //} - - if (StrICmp(argv[i], "-au") == 0 || StrICmp(argv[i], "/au") == 0) // all users - { - if (i + 1 < p && StrICmp(argv[i + 1], "y") == 0 || StrICmp(argv[i + 1], "n") == 0) - { - SetupInfo.CommonFolders = (StrICmp(argv[i + 1], "y") == 0); - i++; - continue; - } - // otherwise it's an error - } - - ret = FALSE; - break; - } - } - return ret; -} - -int CALLBACK -WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - OSVERSIONINFO osVersion = {0}; - MSG msg; - - HInstance = hInstance; - - EnableExceptionsOn64(); - - // we do not want critical errors such as "no disk in drive A:" - SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS); - - for (int i = 0; i < 256; i++) - LowerCase[i] = (char)CharLower((LPTSTR)(DWORD_PTR)i); - - lstrcpy(MAINWINDOW_TITLE, LoadStr(IDS_MAINWINDOWTITLE)); - - PreviousVerOfFileToIncrementContent[0] = 0; - - SetupInfo.ShortcutInDesktop = TRUE; - SetupInfo.ShortcutInStartMenu = TRUE; - //SetupInfo.PinToTaskbar = TRUE; - SetupInfo.CommonFolders = TRUE; - SetupInfo.RunProgram = TRUE; - SetupInfo.ViewReadme = FALSE; - SetupInfo.Silent = FALSE; - - GetModuleFileName(NULL, ModulePath, MAX_PATH); - *(strrchr(ModulePath, '\\')) = '\0'; // Strip setup.exe off path - GetFolderPath(CSIDL_WINDOWS, WindowsDirectory); - GetFolderPath(CSIDL_SYSTEM, SystemDirectory); - GetFolderPath(CSIDL_PROGRAM_FILES, ProgramFilesDirectory); - - if (!GetCmdLineOptions(lpCmdLine)) - { - MessageBox(HWizardDialog, LoadStr(ERROR_CMDLINE), MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - return FALSE; - } - - if (!OpenInfFile()) - { - return FALSE; - } - - if (SetupInfo.UseLicenseFile && !LoadTextFile(SetupInfo.LicenseFilePath, SetupInfo.License, 100000) && !SetupInfo.Silent) - { - MessageBox(HWizardDialog, LoadStr(ERROR_LOADLICENSE), MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - return FALSE; - } - - if (SetupInfo.Silent) - { - GetFoldersPaths(); // based on SetupInfo.CommonFolders extract the folders - if (FindOutIfThisIsUpgrade(NULL)) // returns FALSE only if it cannot continue (we cannot upgrade a newer version) - { - BOOL cont = TRUE; - if (!SetupInfo.UninstallExistingVersion) - DeleteAutoImportConfigMarker(SetupInfo.AutoImportConfig); - else - cont = DoUninstall(NULL, NULL); // returns FALSE if a restart is required or the uninstall failed - if (cont) - DoInstallation(); - } - } - else - { - if (!CreateWizard()) - { - if (!SetupInfo.Silent) - MessageBox(NULL, LoadStr(ERROR_CREATEWIZARD), MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - return FALSE; - } - - while (GetMessage(&msg, NULL, 0, 0)) - { - if (HWizardDialog == NULL || !IsDialogMessage(HWizardDialog, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - } - return 0; -} - -BOOL RegisterString( - LPSTR pszKey, - LPSTR pszValue, - LPSTR pszData) -{ - - HKEY hKey; - DWORD dwDisposition; - - // - // Create the key, if it exists it will be opened - // - - if (ERROR_SUCCESS != - RegCreateKeyEx( - HKEY_LOCAL_MACHINE, // handle of an open key - pszKey, // address of subkey name - 0, // reserved - NULL, // address of class string - REG_OPTION_NON_VOLATILE, // special options flag - KEY_ALL_ACCESS, // desired security access - NULL, // address of key security structure - &hKey, // address of buffer for opened handle - &dwDisposition)) // address of disposition value buffer - { - return FALSE; - } - - // - // Write the value and it's data to the key - // - - if (ERROR_SUCCESS != - RegSetValueEx( - hKey, // handle of key to set value for - pszValue, // address of value to set - 0, // reserved - REG_SZ, // flag for value type - pszData, // address of value data - lstrlen(pszData))) // size of value data - { - - RegCloseKey(hKey); - return FALSE; - } - - // - // Close the key - // - - RegCloseKey(hKey); - - return TRUE; -} - -BOOL GetRegString(HKEY hRootKey, LPSTR pszKey, LPSTR pszValue, LPSTR pszData) -{ - HKEY hKey; - BOOL ret = FALSE; - if (RegOpenKeyEx(hRootKey, pszKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) - { - DWORD dwDataSize = MAX_PATH - 1; - DWORD dwValueType = REG_SZ; - if (RegQueryValueEx(hKey, pszValue, 0, &dwValueType, pszData, &dwDataSize) == ERROR_SUCCESS) - { - ret = TRUE; - if (pszData[dwDataSize] != 0) - pszData[dwDataSize] = 0; - } - RegCloseKey(hKey); - } - if (!ret) - pszData[0] = 0; - return ret; -} - diff --git a/src/setup/infinst.h b/src/setup/infinst.h deleted file mode 100644 index 89bb5ca9..00000000 --- a/src/setup/infinst.h +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -BOOL OpenInfFile(); -BOOL DoInstallation(); -BOOL DoUninstall(HWND hParent, BOOL* needRestart); -BOOL DeleteAutoImportConfigMarker(const char* autoImportConfig); -BOOL FindConflictWithAnotherVersion(BOOL* sameOrOlderVersion, BOOL* sameVersion, /*BOOL *sameOrOlderVersionIgnoringBuild, BOOL *sameVersionIgnoringBuild, */ BOOL* foundRemoveLog); -BOOL RefreshDesktop(BOOL sleep); -BOOL GetRegistryDWORDValue(const char* line, DWORD* retVal); -BOOL FindOutIfThisIsUpgrade(HWND hDlg); -void ReadPreviousVerOfFileToIncrementContent(); -WORD GetCurDispLangID(); - -// -// commands -// -#define ID_INSTALL 100 -#define ID_STOPINSTALL 101 -#define ID_WIZARDDONE 102 - -// -// typedefs -// -typedef struct tagINSTALLINFO -{ - char ApplicationName[MAX_PATH]; // extracted from the INF file - char ApplicationNameVer[MAX_PATH]; // including the version - char DefaultDirectory[MAX_PATH]; // extracted from the INF file - // char UseLastDirectory[MAX_PATH]; // extracted from the INF file - char LastDirectories[3000]; // extracted from the INF file - char License[100000]; // loaded from LICENSE.TXT - char ViewReadmePath[MAX_PATH]; // extracted from the INF file - char CheckRunningApps[MAX_PATH]; // extracted from the INF file - char RunProgramPath[MAX_PATH]; // extracted from the INF file - char RunProgramQuietPath[MAX_PATH]; // extracted from the INF file - char IncrementFileContentSrc[5000]; // extracted from the INF file - char IncrementFileContentDst[5000]; // extracted from the INF file - char EnsureSalamander25Dir[5000]; // extracted from the INF file - char UnistallRunProgramQuietPath[MAX_PATH]; // extracted from the INF file - char SaveRemoveLog[MAX_PATH]; // extracted from the INF file - char LicenseFilePath[MAX_PATH]; // extracted from the INF file - char FirstReadme[100000]; // loaded using FirstReadmeFilePath - char FirstReadmeFilePath[MAX_PATH]; // extracted from the INF file - BOOL UseFirstReadme; - char AutoImportConfig[MAX_PATH]; // extracted from the INF file - char SLGLanguages[5000]; // extracted from the INF file - char WERLocalDumps[5000]; // extracted from the INF file - - char RegPathVal['Z' - 'A' + 1][MAX_PATH]; - - BOOL UseLicenseFile; // does a license file exist - should the installer go through this window? - - char CreateDirectory[MAX_PATH]; // user confirmed creating this directory - - BOOL UninstallExistingVersion; // should we uninstall the existing version of the application? - BOOL TheExistingVersionIsSame; // is the version being overwritten the same as the one we install? - - char CopySection[400000]; - char CopyFrom[200000]; - char CopyTo[200000]; - BYTE CopyFlags[10000]; - int CopyCount; - - // it occurred to me that we can calculate the total size on the user's machine from the unpacked files - // and thus simplify preparing setup.inf - // DWORD SpaceRequired; - - BOOL RebootNeeded; // after the installation finishes a reboot will be recommended - - char ShortcutSection[100000]; - BOOL DesktopPresent; - BOOL StartMenuPresent; - BOOL Silent; // TRUE = silent installation; FALSE = the classic UI with windows - - char CreateDirsSection[100000]; - int CreateDirsCount; - - char TmpSection[500000]; // buffer used for registry data - - char InfFile[100000]; // because the installer cannot read the INF file directly - - // uninstall - char UnpinFromTaskbar[100000]; - char RemoveFiles[400000]; - char RemoveDirs[100000]; - char RemoveRegValues[100000]; - char RemoveRegKeys[100000]; - char RemoveShellExts[100000]; - - BOOL ShortcutInDesktop; - BOOL ShortcutInStartMenu; - //BOOL PinToTaskbar; - BOOL CommonFolders; - - BOOL ViewReadme; - BOOL RunProgram; - BOOL RunProgramQuiet; - - BOOL SkipChooseDir; - - BOOL LoadOldRemoveLog; - char OldRemoveOptions[100000]; - - int DisplayWelcomeWarning; // 0 - no warning - -} INSTALLINFO; - -// -// globals -// -extern HINSTANCE HInstance; // current instance -extern INSTALLINFO SetupInfo; // a structure containing the review information -extern HWND HWizardDialog; -extern HWND HProgressDialog; -extern char InfFileName[MAX_PATH]; -extern char ModulePath[MAX_PATH]; -extern char WindowsDirectory[MAX_PATH]; -extern char SystemDirectory[MAX_PATH]; -extern char ProgramFilesDirectory[MAX_PATH]; - -extern char DesktopDirectory[MAX_PATH]; -extern char StartMenuDirectory[MAX_PATH]; -extern char StartMenuProgramDirectory[MAX_PATH]; -extern char QuickLaunchDirectory[MAX_PATH]; - -extern BOOL SfxDirectoriesValid; -extern char SfxDirectories[7][MAX_PATH]; - -extern HWND SfxDlg; // SFX7ZIP window that launched this setup.exe (before setup.exe exits we show and activate it so the installed readme and Salam can be launched from it) -extern BOOL RunBySfx; // TRUE if setup.exe was started with the /runbysfx parameter - -extern char MAINWINDOW_TITLE[100]; - -extern const char* INF_PRIVATE_SECTION; -extern const char* INF_VIEWREADME; -extern const char* INF_RUNPROGRAM; -extern const char* INF_RUNPROGRAMQUIET; -extern const char* INF_UNINSTALLRUNPROGRAMQUIET; -extern const char* INF_SAVEREMOVELOG; -extern const char* INF_SKIPCHOOSEDIR; - -extern DWORD CCMajorVer; -extern DWORD CCMinorVer; -extern DWORD CCMajorVerNeed; -extern DWORD CCMinorVerNeed; - -// options from the command line -extern char CmdLineDestination[MAX_PATH]; // if the string is not empty, it specifies the target directory (otherwise the default is used) - -extern char PreviousVerOfFileToIncrementContent[10000]; // contents of the just-uninstalled plugins.ver - -// -//functions -// -BOOL CreateWizard(); -BOOL StopInstalling(); -void InstallDone(); -void CenterWindow(HWND hWindow); // centers to the main window - -char* LoadStr(int resID); // fetches a string from resources -void InsertProgramName(char* str, BOOL version); // inserts the installed program name into str -void InsertAppName(HWND hDlg, int resID, BOOL version); -BOOL QueryFreeSpace(char* driveSpec, LONGLONG* spaceRequired); -BOOL GetSpecialFolderPath(int folder, char* path); -void GetRootPath(char* root, const char* path); -char* strrchr(const char* string, int c); -int StrICmp(const char* s1, const char* s2); -void ExpandPath(char* path); - -void ExtractCopySection(); -void ExtractShortcutSection(); -void ExtractCreateDirsSection(); -BOOL DoGetRegistryVarSection(); - -BOOL GetRegString(HKEY hRootKey, LPSTR pszKey, LPSTR pszValue, LPSTR pszData); - -void SetProgressMax(int max); -void SetProgressPos(int pos); -void SetFromTo(const char* from, const char* to); - -BOOL LoadLastDirectory(); - -INT_PTR CALLBACK CommonControlsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - -BOOL RemoveAllSubKeys(HKEY hKey); -HKEY GetRootHandle(const char* root); - -BOOL FileExist(const char* fileName); - -BOOL StoreExecuteInfo(const char* cmdLineViewer, const char* cmdLineProgram, BOOL execViewer, BOOL execProgram); - -LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); - -DWORD MyStrToDWORD(const char* num); -int HandleErrorM(int titleID, const char* msg, unsigned long err); -BOOL LoadRemoveLog(); -BOOL LoadTextFile(const char* fileName, char* buff, int buffMax); -void GetFoldersPaths(); - -#define WM_USER_STARTINSTALL (WM_APP + 100) // start the installation -#define WM_USER_STARTUNINSTALL (WM_APP + 101) // start the uninstallation -#define WM_USER_SHOWACTSFX7ZIP (WM_APP + 666) // show and activate the SFX7ZIP dialog (the number is shared with SFX7ZIP) -#define WM_USER_CLOSEWIZARDDLG (WM_APP + 667) // delayed closing of the wizard (wait until Readme and Salamander start; if the dialog closes immediately, the launched apps are not activated and remain in the background while other windows stay on top) diff --git a/src/setup/instwiz.c b/src/setup/instwiz.c deleted file mode 100644 index 8d984c2c..00000000 --- a/src/setup/instwiz.c +++ /dev/null @@ -1,1950 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "precomp.h" -#include -#include - -#include "infinst.h" -#include "resource.h" - -#pragma comment(lib, "Shlwapi.lib") - -// from windowsx.h -#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) -#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) - -// global license flag -BOOL gLicenseAccepted = FALSE; -HWND HWizardDialog = NULL; -HWND HProgressDialog = NULL; - -// -// constants -// -#define NUM_PAGES 8 -#define MAX_BUF 5000 -#define MAX_LINE 512 -int PagesCount; - -struct CWizardPage -{ - int ResID; - DLGPROC DlgProc; - char Title[100]; - HWND HWindow; -}; - -struct CWizardPage WizardPages[NUM_PAGES] = {0}; - -#define _TPD_IDC_BACK 5 -#define _TPD_IDC_NEXT IDOK -#define _TPD_IDC_EXIT IDCANCEL - -#define _TPD_LEFTMARGIN 4 // left margin padding for the wizard button bar -#define _TPD_BOTTOMMARGIN 26 // height of the bottom strip beneath the dialogs -#define _TPD_BUTTON_W 50 // width of the buttons -#define _TPD_BUTTON_H 14 // height of the buttons - -RECT ChildDialogRect; // position of the child dialog within the wizard -HWND HChildDialog = NULL; // current child dialog -int CurrentPageIndex = -1; // current page number -HFONT HBoldFont = NULL; -HFONT HULFont = NULL; - -BOOL RunningInLowColors = FALSE; // are we running in 256 colors or fewer? - -BOOL CloseWizardDlgOnDeact = FALSE; - -BOOL SelectPage(int pageIndex); - -void NextIsDefault() -{ - SendDlgItemMessage(HWizardDialog, _TPD_IDC_BACK, BM_SETSTYLE, BS_PUSHBUTTON, TRUE); - SendDlgItemMessage(HWizardDialog, _TPD_IDC_NEXT, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE); - SendDlgItemMessage(HWizardDialog, _TPD_IDC_EXIT, BM_SETSTYLE, BS_PUSHBUTTON, TRUE); -} - -void RemoveIconIfNoColors(HWND hDlg) -{ - // the high-DPI version of the icon is missing; without it the UI looks better anyway - always drop it - DestroyWindow(GetDlgItem(hDlg, IDC_INSTALL_ICON)); - return; - //if (RunningInLowColors) - // DestroyWindow(GetDlgItem(hDlg, IDC_INSTALL_ICON)); - //else - //{ - // HWND hItem = GetDlgItem(hDlg, IDC_INSTALL_ICON); - // SetParent(hItem, GetDlgItem(hDlg, IDC_WHITE_RECT)); - //} -} - -//************************************************************************************ -// -// CommonControlsDlgProc -// - -INT_PTR CALLBACK -CommonControlsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - char buff[500]; - char buff2[500]; - wsprintf(buff, "%d.%d", CCMajorVer, CCMinorVer); - SetDlgItemText(hDlg, IDC_CC_VERSION, buff); - - GetDlgItemText(hDlg, IDC_CC_VERSION_NEED, buff, 500); - wsprintf(buff2, buff, CCMajorVerNeed, CCMinorVerNeed); - SetDlgItemText(hDlg, IDC_CC_VERSION_NEED, buff2); - - CenterWindow(hDlg); - - break; - } - - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDCANCEL: - case IDOK: - { - EndDialog(hDlg, wParam); - return TRUE; - } - } - break; - } - } - return FALSE; -} - -//************************************************************************************ -// -// WelcomeDlgProc -// - -void DrawLogoBitmap(HDC hDC, RECT r) -{ - BITMAP bmp; - HBITMAP hBitmap = LoadBitmap(HInstance, MAKEINTRESOURCE(IDB_WELCOME)); - HDC hMemDC = CreateCompatibleDC(NULL); - HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); - GetObject(hBitmap, sizeof(bmp), &bmp); - BitBlt(hDC, r.right - bmp.bmWidth, 0, bmp.bmWidth, bmp.bmHeight, hMemDC, 0, 0, SRCCOPY); - SelectObject(hMemDC, hOldBitmap); - DeleteObject(hBitmap); - DeleteDC(hMemDC); -} - -INT_PTR CALLBACK -WelcomeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - SendMessage(HWizardDialog, DM_SETDEFID, _TPD_IDC_NEXT, 0); - InsertAppName(hDlg, IDC_WLC_A, FALSE); - InsertAppName(hDlg, IDC_WLC_B, TRUE); - if (SetupInfo.DisplayWelcomeWarning == 1 || SetupInfo.DisplayWelcomeWarning == 2) - SetDlgItemText(hDlg, IDC_WLC_WARNING, LoadStr(SetupInfo.DisplayWelcomeWarning == 1 ? IDS_PREVIEWBUILDWARNING : IDS_BETAWARNING)); - break; - } - - case WM_CTLCOLORSTATIC: - { - if ((HWND)lParam == GetDlgItem(hDlg, IDC_WLC_A)) - SelectObject((HDC)wParam, HBoldFont); - if ((HWND)lParam == GetDlgItem(hDlg, IDC_WLC_WARNING)) - SelectObject((HDC)wParam, HBoldFont); - return (INT_PTR)GetStockObject(WHITE_BRUSH); - } - - case WM_ERASEBKGND: - { - HDC hDC = (HDC)wParam; - RECT r; - GetClientRect(hDlg, &r); - FillRect(hDC, &r, (HBRUSH)(COLOR_WINDOW + 1)); - DrawLogoBitmap(hDC, r); - return TRUE; // background is erased - } - - case WM_NOTIFY: - { - NMHDR* hdr = (NMHDR*)lParam; - switch (hdr->code) - { - case PSN_SETACTIVE: - { - SetDlgItemText(HWizardDialog, _TPD_IDC_BACK, LoadStr(IDS_WZR_BACK)); - SetDlgItemText(HWizardDialog, _TPD_IDC_NEXT, LoadStr(IDS_WZR_NEXT)); - SetDlgItemText(HWizardDialog, _TPD_IDC_EXIT, LoadStr(IDS_WZR_EXIT)); - NextIsDefault(); - SetFocus(GetDlgItem(HWizardDialog, _TPD_IDC_NEXT)); - break; - } - } - break; - } - } - - return FALSE; -} - -//************************************************************************************ -// -// ReadmeDlgProc -// - -WNDPROC PrevWndProc = NULL; - -LRESULT CALLBACK -MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_KEYDOWN: - { - if (wParam == VK_RETURN) - PostMessage(HWizardDialog, WM_COMMAND, _TPD_IDC_NEXT, 0); - break; - } - } - if (PrevWndProc == NULL) - return DefWindowProc(hWnd, uMsg, wParam, lParam); - else - return CallWindowProc(PrevWndProc, hWnd, uMsg, wParam, lParam); -} - -INT_PTR CALLBACK -ReadmeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - RemoveIconIfNoColors(hDlg); - PrevWndProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg, IDC_SLA_LICENSE), GWLP_WNDPROC, (LPARAM)MainWindowProc); - SetWindowText(GetDlgItem(hDlg, IDC_SLA_LICENSE), SetupInfo.FirstReadme); - InsertAppName(hDlg, IDC_SLA_BOTTOM, FALSE); - break; - } - - case WM_CTLCOLORSTATIC: - { - int childID = (int)(DWORD_PTR)GetMenu((HWND)lParam); - - if (childID == IDC_BOLDWHITE_TEXT) - SelectObject((HDC)wParam, HBoldFont); - - if (childID == IDC_WHITE_RECT || childID == IDC_BOLDWHITE_TEXT || childID == IDC_NORMALWHITE_TEXT) - return (INT_PTR)GetStockObject(WHITE_BRUSH); - break; - } - - case WM_COMMAND: - { - if (LOWORD(wParam) == IDCANCEL) - PostMessage(HWizardDialog, WM_COMMAND, IDCANCEL, 0); - break; - } - - case WM_NOTIFY: - { - NMHDR* hdr = (NMHDR*)lParam; - switch (hdr->code) - { - case PSN_SETACTIVE: - { - NextIsDefault(); - SetFocus(GetDlgItem(hDlg, IDC_SLA_LICENSE)); - break; - } - } - break; - } - } - return FALSE; -} - -//************************************************************************************ -// -// LicenseDlgProc -// - -/* -WNDPROC PrevWndProc = NULL; -LRESULT CALLBACK -MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_KEYDOWN: - { - if (wParam == VK_RETURN) - PostMessage(HWizardDialog, WM_COMMAND, _TPD_IDC_NEXT, 0); - break; - } - } - if (PrevWndProc == NULL) - return DefWindowProc(hWnd, uMsg, wParam, lParam); - else - return CallWindowProc(PrevWndProc, hWnd, uMsg, wParam, lParam); -} -*/ -INT_PTR CALLBACK -LicenseDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - RemoveIconIfNoColors(hDlg); - PrevWndProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg, IDC_SLA_LICENSE), GWLP_WNDPROC, (LPARAM)MainWindowProc); - SetWindowText(GetDlgItem(hDlg, IDC_SLA_LICENSE), SetupInfo.License); - InsertAppName(hDlg, IDC_SLA_BOTTOM, FALSE); - break; - } - - case WM_CTLCOLORSTATIC: - { - int childID = (int)(DWORD_PTR)GetMenu((HWND)lParam); - - if (childID == IDC_BOLDWHITE_TEXT) - SelectObject((HDC)wParam, HBoldFont); - - if (childID == IDC_WHITE_RECT || childID == IDC_BOLDWHITE_TEXT || childID == IDC_NORMALWHITE_TEXT) - return (INT_PTR)GetStockObject(WHITE_BRUSH); - break; - } - - case WM_COMMAND: - { - if (LOWORD(wParam) == IDCANCEL) - PostMessage(HWizardDialog, WM_COMMAND, IDCANCEL, 0); - break; - } - - case WM_NOTIFY: - { - NMHDR* hdr = (NMHDR*)lParam; - switch (hdr->code) - { - case PSN_SETACTIVE: - { - SetDlgItemText(HWizardDialog, _TPD_IDC_NEXT, LoadStr(IDS_WZR_YES)); - SetDlgItemText(HWizardDialog, _TPD_IDC_EXIT, LoadStr(IDS_WZR_NO)); - NextIsDefault(); - SetFocus(GetDlgItem(hDlg, IDC_SLA_LICENSE)); - break; - } - - case PSN_KILLACTIVE: - { - SetDlgItemText(HWizardDialog, _TPD_IDC_NEXT, LoadStr(IDS_WZR_NEXT)); - SetDlgItemText(HWizardDialog, _TPD_IDC_EXIT, LoadStr(IDS_WZR_EXIT)); - break; - } - } - break; - } - } - return FALSE; -} - -//************************************************************************************ -// -// DestinationDlgProc -// - -struct CBrowseData -{ - const char* Title; - const char* InitDir; -}; - -int CALLBACK DirectoryBrowse(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) -{ - if (uMsg == BFFM_INITIALIZED) - { - CenterWindow(hwnd); - - // set the header - SetWindowText(hwnd, ((struct CBrowseData*)lpData)->Title); - if (((struct CBrowseData*)lpData)->InitDir != NULL) - { - char path[MAX_PATH]; - lstrcpy(path, ((struct CBrowseData*)lpData)->InitDir); - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)path); - } - } - if (uMsg == BFFM_SELCHANGED) - { - if ((ITEMIDLIST*)lParam != NULL) - { - char path[MAX_PATH]; - BOOL ret = SHGetPathFromIDList((ITEMIDLIST*)lParam, path); - SendMessage(hwnd, BFFM_ENABLEOK, 0, ret); - } - } - return 0; -} - -BOOL GetTargetDirectory(HWND parent, const char* title, const char* comment, - char* path, BOOL onlyNet, const char* initDir) -{ - IMalloc* alloc; - BOOL ret; - LPITEMIDLIST res; - struct CBrowseData bd; - BROWSEINFO bi; - char display[MAX_PATH]; - ITEMIDLIST* pidl; // select the root folder - if (onlyNet) - SHGetSpecialFolderLocation(parent, CSIDL_NETWORK, &pidl); - else - pidl = NULL; - - // open the dialog - bi.hwndOwner = parent; - bi.pidlRoot = pidl; - bi.pszDisplayName = display; - bi.lpszTitle = comment; - bi.ulFlags = BIF_RETURNONLYFSDIRS; - bi.lpfn = DirectoryBrowse; - bd.Title = title; - bd.InitDir = initDir; - bi.lParam = (LPARAM)&bd; - res = SHBrowseForFolder(&bi); - ret = FALSE; // return value - if (res != NULL) - { - SHGetPathFromIDList(res, path); - ret = TRUE; - } - // release the item ID lists - if (SUCCEEDED(CoGetMalloc(1, &alloc))) - { - if (alloc->lpVtbl->DidAlloc(alloc, pidl) == 1) - alloc->lpVtbl->Free(alloc, pidl); - if (alloc->lpVtbl->DidAlloc(alloc, res) == 1) - alloc->lpVtbl->Free(alloc, res); - alloc->lpVtbl->Release(alloc); - } - return ret; -} - -void GetRootPath(char* root, const char* path) -{ - if (path[0] == '\\' && path[1] == '\\') // UNC - { - int len; - const char* s = path + 2; - while (*s != 0 && *s != '\\') - s++; - s++; // '\\' - while (*s != 0 && *s != '\\') - s++; - len = 0; - while (len < s - path) - { - *root = *(path + len); - len++; - } - // MoveMemory(root, path, s - path); - root[s - path] = '\\'; - root[(s - path) + 1] = 0; - } - else - { - lstrcpy(root, " :\\"); - root[0] = path[0]; - } -} - -unsigned __int64 MyGetFileSize(const char* fileName) -{ - unsigned __int64 size = 0; - HANDLE hFile = CreateFile(fileName, GENERIC_READ, - FILE_SHARE_READ, NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - DWORD sizeDW = GetFileSize(hFile, NULL); - size = (unsigned __int64)sizeDW; - CloseHandle(hFile); - } - return size; -} - -unsigned __int64 GetRequiredSpace() -{ - char src[MAX_PATH]; - const char* from; - const char* to; - int i; - unsigned __int64 size; - - from = SetupInfo.CopyFrom; - to = SetupInfo.CopyTo; - size = 0; - - for (i = 0; i < SetupInfo.CopyCount; i++) - { - lstrcpy(src, from); - ExpandPath(src); - size += MyGetFileSize(src); - - from += lstrlen(from) + 1; - to += lstrlen(to) + 1; - } - return size; -} - -BOOL FindOutIfThisIsUpgrade(HWND hDlg) -{ - BOOL sameOrOlderVersion; - BOOL sameVersion; - BOOL foundRemoveLog; - - SetupInfo.UninstallExistingVersion = FALSE; - SetupInfo.TheExistingVersionIsSame = FALSE; - - // verify whether the target contains an EXE with the same name - if (FindConflictWithAnotherVersion(&sameOrOlderVersion, &sameVersion, &foundRemoveLog)) - { - // if it is a newer version of Salamander, we do not know how it should be uninstalled and it makes no sense - // to consider the presence of a remove log, because it might be a different uninstall technology -- show IDS_CONFLICTWITHNEWER - - // if it is the same or an older version of Salamander and no remove log is found, overwrite it without asking - if (!(sameOrOlderVersion && !foundRemoveLog)) - { - int cnfrmRet = IDOK; - if (!SetupInfo.Silent) - { - int textID; - char text[1024]; - if (sameOrOlderVersion) - textID = sameVersion ? IDS_CONFLICTSAME : IDS_CONFLICTPRIOR; - else - textID = IDS_CONFLICTWITHNEWER; - wsprintf(text, LoadStr(textID), SetupInfo.DefaultDirectory); - cnfrmRet = MessageBox(hDlg, text, MAINWINDOW_TITLE, (sameOrOlderVersion ? MB_OKCANCEL : MB_OK) | MB_ICONINFORMATION); - } - if (!sameOrOlderVersion || cnfrmRet == IDCANCEL) - { - return FALSE; - } - else - { - SetupInfo.UninstallExistingVersion = TRUE; - SetupInfo.TheExistingVersionIsSame = sameVersion; - } - } - } - return TRUE; -} - -INT_PTR CALLBACK -DestinationDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - RemoveIconIfNoColors(hDlg); - InsertAppName(hDlg, IDC_CDL_1, FALSE); - SendDlgItemMessage(hDlg, IDC_CDL_PATH, WM_SETTEXT, 0, - (LPARAM)SetupInfo.DefaultDirectory); - break; - } - - case WM_CTLCOLORSTATIC: - { - int childID = (int)(DWORD_PTR)GetMenu((HWND)lParam); - - if (childID == IDC_BOLDWHITE_TEXT) - SelectObject((HDC)wParam, HBoldFont); - - if (childID == IDC_WHITE_RECT || childID == IDC_BOLDWHITE_TEXT || childID == IDC_NORMALWHITE_TEXT) - return (INT_PTR)GetStockObject(WHITE_BRUSH); - break; - } - - case WM_COMMAND: - { - if (LOWORD(wParam == IDC_CDL_BROWSE)) - { - char buff[MAX_PATH]; - char* s; - GetDlgItemText(hDlg, IDC_CDL_PATH, buff, MAX_PATH); - SendDlgItemMessage(hDlg, IDC_CDL_PATH, WM_GETTEXT, MAX_PATH, (LPARAM)buff); - - s = LoadStr(IDS_CHOOSEDIR); - if (GetTargetDirectory(hDlg, s, s, buff, FALSE, buff)) - { - SendDlgItemMessage(hDlg, IDC_CDL_PATH, WM_SETTEXT, 0, (LPARAM)buff); - } - return 0; - } - break; - } - - case WM_NOTIFY: - { - NMHDR* hdr = (NMHDR*)lParam; - switch (hdr->code) - { - case PSN_SETACTIVE: - { - SendDlgItemMessage(hDlg, IDC_CDL_PATH, EM_SETSEL, 0, -1); - NextIsDefault(); - SetFocus(GetDlgItem(hDlg, IDC_CDL_PATH)); - break; - } - - case PSN_KILLACTIVE: - { - char text[1024]; - if (wParam == 1) - { - BOOL exist; - // BOOL bResult; - int ret; - char buff[MAX_PATH]; - char curDir[MAX_PATH]; - char driveSpec[MAX_PATH]; - char backupDefaultDirectory[MAX_PATH]; - char backupCreateDirectory[MAX_PATH]; - - DWORD bytesPerSector; - DWORD sectorsPerCluster; - DWORD numberOfFreeClusters; - DWORD dummy; - unsigned __int64 freeSpace; - unsigned __int64 requiredSpace; - - // grab the path from the edit box - SendDlgItemMessage(hDlg, IDC_CDL_PATH, WM_GETTEXT, MAX_PATH, (LPARAM)buff); - - if (SetupInfo.EnsureSalamander25Dir[0] != 0) - { - char langPath[MAX_PATH]; - char* end; - lstrcpy(langPath, buff); - end = langPath + lstrlen(langPath); - if (end > langPath && *(end - 1) != '\\') - { - *end = '\\'; - end++; - } - lstrcpy(end, "lang"); - - GetCurrentDirectory(MAX_PATH, curDir); - exist = SetCurrentDirectory(langPath); - SetCurrentDirectory(curDir); - - if (!exist) - { - MessageBox(hDlg, SetupInfo.EnsureSalamander25Dir, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); - return 1; - } - } - - if (lstrcmp(SetupInfo.CreateDirectory, buff) != 0) - { - GetCurrentDirectory(MAX_PATH, curDir); - exist = SetCurrentDirectory(buff); - SetCurrentDirectory(curDir); - - ret = IDOK; - // JRY - removed the confirmation for creating a non-existent directory; other installers do not ask - /* - if (!exist) - { - wsprintf(text, LoadStr(IDS_NODIR), buff); - ret = MessageBox(hDlg, text, MAINWINDOW_TITLE, MB_YESNO | MB_ICONQUESTION); - } - if (ret == IDNO) - { - SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); - return 1; - } - */ - } - - // if(!bResult) - // { - // SetWindowLong(hDlg, DWL_MSGRESULT, TRUE); - // return 1; - // } - - // backup in case of failure - lstrcpy(backupDefaultDirectory, SetupInfo.DefaultDirectory); - lstrcpy(backupCreateDirectory, SetupInfo.CreateDirectory); - - // need to set the globals so that paths expand correctly during the conflict check - lstrcpy(SetupInfo.DefaultDirectory, buff); - lstrcpy(SetupInfo.CreateDirectory, buff); - - if (!FindOutIfThisIsUpgrade(hDlg)) // returns FALSE only if the user does not wish to continue or it is impossible (we cannot upgrade a newer version) - { - // select the path in the edit line to highlight that it should be changed - SetFocus(GetDlgItem(hDlg, IDC_CDL_PATH)); - - // if we would overwrite a newer version or the user does not want to upgrade the existing one, do not allow proceeding - SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); - // restore the previous values instead - lstrcpy(SetupInfo.DefaultDirectory, backupDefaultDirectory); - lstrcpy(SetupInfo.CreateDirectory, backupCreateDirectory); - return 1; - } - - GetRootPath(driveSpec, buff); - - if (!GetDiskFreeSpace(driveSpec, §orsPerCluster, &bytesPerSector, - &numberOfFreeClusters, &dummy)) - { - wsprintf(text, LoadStr(IDS_INVALIDPATH), buff); - MessageBox(hDlg, text, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); - return 1; - } - - freeSpace = (unsigned __int64)bytesPerSector * - (unsigned __int64)sectorsPerCluster * - (unsigned __int64)numberOfFreeClusters; - - requiredSpace = GetRequiredSpace(); - requiredSpace += 100000; // 100KB for the uninstall log (should be more than enough) - - if (freeSpace < requiredSpace) - { - // I downloaded it to try your product but it's failing to install because it thinks there - // isn't enough HD space. It reports space req 2812901, avail 652800. This is wrong since - // MS explorer reports 2.64 GB used, 16.0 GB free. - // My system is new, running Win Pro 2000. Do you know what the problem is? Fix? - // - // John: based on this email I am adding the option to ignore a lack of disk space - wsprintf(text, LoadStr(IDS_NOSPACE), driveSpec, (DWORD)requiredSpace, (DWORD)freeSpace); - ret = MessageBox(hDlg, text, MAINWINDOW_TITLE, MB_OKCANCEL | MB_ICONINFORMATION); - if (ret == IDOK) - { - SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); - return 1; - } - } - - if (lstrlen(buff) > 0) - if (buff[lstrlen(buff) - 1] == '\\') - buff[lstrlen(buff) - 1] = 0; - - SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE); - } - else - SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE); - return 1; - } - } - break; - } - } - return FALSE; -} - -//************************************************************************************ -// -// FolderDlgProc -// - -void GetFoldersPaths() -{ - if (SfxDirectoriesValid) // Vista or later: take the paths stored in the non-elevated process (SFX); when elevating we might switch to the admin user and the paths would differ from what we need - { - lstrcpyn(DesktopDirectory, SetupInfo.CommonFolders ? SfxDirectories[0] : SfxDirectories[1], MAX_PATH); - lstrcpyn(StartMenuDirectory, SetupInfo.CommonFolders ? SfxDirectories[2] : SfxDirectories[3], MAX_PATH); - lstrcpyn(StartMenuProgramDirectory, SetupInfo.CommonFolders ? SfxDirectories[4] : SfxDirectories[5], MAX_PATH); - lstrcpyn(QuickLaunchDirectory, SfxDirectories[6], MAX_PATH); - } - else - { - GetSpecialFolderPath(SetupInfo.CommonFolders ? CSIDL_COMMON_DESKTOPDIRECTORY : CSIDL_DESKTOPDIRECTORY, DesktopDirectory); - GetSpecialFolderPath(SetupInfo.CommonFolders ? CSIDL_COMMON_STARTMENU : CSIDL_STARTMENU, StartMenuDirectory); - GetSpecialFolderPath(SetupInfo.CommonFolders ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, StartMenuProgramDirectory); - // we can obtain CSIDL_COMMON_APPDATA, but adding a shortcut to Quick Launch has no effect, see the NEWS - GetSpecialFolderPath(CSIDL_APPDATA, QuickLaunchDirectory); // always use the user's Quick Launch toolbar - } - if (lstrlen(QuickLaunchDirectory) > 0) - { - if (QuickLaunchDirectory[lstrlen(QuickLaunchDirectory) - 1] == '\\') - QuickLaunchDirectory[lstrlen(QuickLaunchDirectory) - 1] = 0; - lstrcat(QuickLaunchDirectory, "\\Microsoft\\Internet Explorer\\Quick Launch"); - } -} - -void EnableFolderButtons(HWND hDlg) -{ - BOOL enable = SetupInfo.ShortcutInDesktop | - SetupInfo.ShortcutInStartMenu; - EnableWindow(GetDlgItem(hDlg, IDC_SPF_PERSONAL), enable); - EnableWindow(GetDlgItem(hDlg, IDC_SPF_COMMON), enable); - //EnableWindow(GetDlgItem(hDlg, IDC_SPF_PINTOTASKBAR), SetupInfo.ShortcutInStartMenu); - //if (!SetupInfo.ShortcutInStartMenu) - // CheckDlgButton(hDlg, IDC_SPF_PINTOTASKBAR, BST_UNCHECKED); -} - -INT_PTR CALLBACK -FolderDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - RemoveIconIfNoColors(hDlg); - ShowWindow(GetDlgItem(hDlg, IDC_SPF_DESKTOP), SetupInfo.DesktopPresent); - ShowWindow(GetDlgItem(hDlg, IDC_SPF_LINK), SetupInfo.StartMenuPresent); - //ShowWindow(GetDlgItem(hDlg, IDC_SPF_PINTOTASKBAR), SetupInfo.StartMenuPresent); - - ShowWindow(GetDlgItem(hDlg, IDC_SPF_FOLDERS), TRUE); - ShowWindow(GetDlgItem(hDlg, IDC_SPF_COMMON), TRUE); - ShowWindow(GetDlgItem(hDlg, IDC_SPF_PERSONAL), TRUE); - break; - } - - case WM_CTLCOLORSTATIC: - { - int childID = (int)(DWORD_PTR)GetMenu((HWND)lParam); - - if (childID == IDC_BOLDWHITE_TEXT) - SelectObject((HDC)wParam, HBoldFont); - - if (childID == IDC_WHITE_RECT || childID == IDC_BOLDWHITE_TEXT || childID == IDC_NORMALWHITE_TEXT) - return (INT_PTR)GetStockObject(WHITE_BRUSH); - break; - } - - case WM_COMMAND: - { - if (HIWORD(wParam) == BN_CLICKED) - { - SetupInfo.ShortcutInDesktop = SetupInfo.DesktopPresent && IsDlgButtonChecked(hDlg, IDC_SPF_DESKTOP) == BST_CHECKED; - SetupInfo.ShortcutInStartMenu = SetupInfo.StartMenuPresent && IsDlgButtonChecked(hDlg, IDC_SPF_LINK) == BST_CHECKED; - //SetupInfo.PinToTaskbar = SetupInfo.StartMenuPresent && SetupInfo.ShortcutInStartMenu && - // IsDlgButtonChecked(hDlg, IDC_SPF_PINTOTASKBAR) == BST_CHECKED; - - SetupInfo.CommonFolders = IsDlgButtonChecked(hDlg, IDC_SPF_COMMON) == BST_CHECKED; - EnableFolderButtons(hDlg); - } - break; - } - - case WM_NOTIFY: - { - NMHDR* hdr = (NMHDR*)lParam; - switch (hdr->code) - { - case PSN_SETACTIVE: - { - CheckDlgButton(hDlg, IDC_SPF_DESKTOP, SetupInfo.ShortcutInDesktop ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_SPF_LINK, SetupInfo.ShortcutInStartMenu ? BST_CHECKED : BST_UNCHECKED); - //CheckDlgButton(hDlg, IDC_SPF_PINTOTASKBAR, SetupInfo.PinToTaskbar ? BST_CHECKED : BST_UNCHECKED); - - CheckDlgButton(hDlg, IDC_SPF_PERSONAL, SetupInfo.CommonFolders ? BST_UNCHECKED : BST_CHECKED); - CheckDlgButton(hDlg, IDC_SPF_COMMON, SetupInfo.CommonFolders ? BST_CHECKED : BST_UNCHECKED); - - EnableFolderButtons(hDlg); - SetFocus(GetDlgItem(HWizardDialog, _TPD_IDC_NEXT)); - NextIsDefault(); - break; - } - - case PSN_KILLACTIVE: - { - SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(0, BN_CLICKED), 0); - - GetFoldersPaths(); // extract the folders according to SetupInfo.CommonFolders - break; - } - } - break; - } - } - return FALSE; -} - -//************************************************************************************ -// -// FinishDlgProc -// - -void AddString(HWND hEdit, char* text) -{ - SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)text); -} - -INT_PTR CALLBACK -FinishDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - RemoveIconIfNoColors(hDlg); - InsertAppName(hDlg, IDC_NORMALWHITE_TEXT, FALSE); - SetupInfo.ShortcutInDesktop &= SetupInfo.DesktopPresent; - SetupInfo.ShortcutInStartMenu &= SetupInfo.StartMenuPresent; - //SetupInfo.PinToTaskbar &= SetupInfo.StartMenuPresent; - break; - } - - case WM_CTLCOLORSTATIC: - { - int childID = (int)(DWORD_PTR)GetMenu((HWND)lParam); - - if (childID == IDC_BOLDWHITE_TEXT) - SelectObject((HDC)wParam, HBoldFont); - - if (childID == IDC_WHITE_RECT || childID == IDC_BOLDWHITE_TEXT || childID == IDC_NORMALWHITE_TEXT) - return (INT_PTR)GetStockObject(WHITE_BRUSH); - break; - } - - case WM_NOTIFY: - { - NMHDR* hdr = (NMHDR*)lParam; - switch (hdr->code) - { - case PSN_SETACTIVE: - { - BOOL folders; - HWND hEdit = GetDlgItem(hDlg, IDC_CYS_TEXT); - - SetWindowText(hEdit, ""); - AddString(hEdit, LoadStr(SetupInfo.UninstallExistingVersion ? IDS_TARGETDIRUPGRADE : IDS_TARGETDIR)); - AddString(hEdit, "\r\n"); - AddString(hEdit, " "); - AddString(hEdit, SetupInfo.DefaultDirectory); - AddString(hEdit, "\r\n"); - AddString(hEdit, "\r\n"); - - folders = SetupInfo.ShortcutInDesktop | - SetupInfo.ShortcutInStartMenu; - if (folders) - { - if (SetupInfo.CommonFolders) - AddString(hEdit, LoadStr(IDS_COMMON)); - else - AddString(hEdit, LoadStr(IDS_PERSONAL)); - AddString(hEdit, "\r\n"); - - if (SetupInfo.ShortcutInDesktop) - { - AddString(hEdit, " "); - AddString(hEdit, LoadStr(IDS_INSERT_DESKTOP)); - AddString(hEdit, "\r\n"); - } - - if (SetupInfo.ShortcutInStartMenu) - { - AddString(hEdit, " "); - AddString(hEdit, LoadStr(IDS_INSERT_MENU)); - AddString(hEdit, "\r\n"); - } - - AddString(hEdit, "\r\n"); - } - - SetDlgItemText(HWizardDialog, _TPD_IDC_NEXT, LoadStr(IDS_WZR_INSTALL)); - NextIsDefault(); - SetFocus(GetDlgItem(HWizardDialog, _TPD_IDC_NEXT)); - break; - } - - case PSN_KILLACTIVE: - { - if (wParam == 0) // back - { - SetDlgItemText(HWizardDialog, _TPD_IDC_NEXT, LoadStr(IDS_WZR_NEXT)); - break; - } - } - } - break; - } - } - return FALSE; -} - -//************************************************************************************ -// -// UninstallDlgProc -// - -BOOL SaveLastDirectory(); - -INT_PTR CALLBACK -UninstallDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - // save immediately after starting the installation, because if a restart is required we want to push to the correct location next time - SaveLastDirectory(); - - RemoveIconIfNoColors(hDlg); - PreviousVerOfFileToIncrementContent[0] = 0; - if (!SetupInfo.UninstallExistingVersion) - { - DeleteAutoImportConfigMarker(SetupInfo.AutoImportConfig); - ShowWindow(hDlg, SW_HIDE); - PostMessage(HWizardDialog, WM_COMMAND, _TPD_IDC_NEXT, 0); - } - else - { - ShowWindow(hDlg, SW_SHOW); - PostMessage(hDlg, WM_USER_STARTUNINSTALL, 0, 0); - } - break; - } - - case WM_USER_STARTUNINSTALL: - { - BOOL needRestart = FALSE; - HProgressDialog = hDlg; - UpdateWindow(hDlg); - if (!DoUninstall(hDlg, &needRestart)) - { - char buff[1024]; - if (needRestart) - { - wsprintf(buff, LoadStr(IDS_INSTNEEDRESTART), SetupInfo.ApplicationName); - MessageBox(hDlg, buff, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - } - else - { - wsprintf(buff, LoadStr(IDS_INSTFAILED), SetupInfo.ApplicationName); - MessageBox(hDlg, buff, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - } - PostQuitMessage(0); - return 0; - } - PostMessage(HWizardDialog, WM_COMMAND, _TPD_IDC_NEXT, 0); - return 0; - } - - case WM_CTLCOLORSTATIC: - { - int childID = (int)(DWORD_PTR)GetMenu((HWND)lParam); - - if (childID == IDC_BOLDWHITE_TEXT) - SelectObject((HDC)wParam, HBoldFont); - - if (childID == IDC_WHITE_RECT || childID == IDC_BOLDWHITE_TEXT || childID == IDC_NORMALWHITE_TEXT) - return (INT_PTR)GetStockObject(WHITE_BRUSH); - break; - } - - case WM_NOTIFY: - { - NMHDR* hdr = (NMHDR*)lParam; - switch (hdr->code) - { - case PSN_SETACTIVE: - { - ShowWindow(GetDlgItem(HWizardDialog, _TPD_IDC_BACK), SW_HIDE); - ShowWindow(GetDlgItem(HWizardDialog, _TPD_IDC_NEXT), SW_HIDE); - // SetDlgItemText(HWizardDialog, _TPD_IDC_EXIT, LoadStr(IDS_WZR_FINISH)); - EnableWindow(GetDlgItem(HWizardDialog, _TPD_IDC_EXIT), FALSE); - - SendMessage(HWizardDialog, DM_SETDEFID, _TPD_IDC_EXIT, 0); - SendDlgItemMessage(HWizardDialog, _TPD_IDC_EXIT, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE); - SetFocus(GetDlgItem(HWizardDialog, _TPD_IDC_EXIT)); - break; - } - } - break; - } - } - return FALSE; -} - -//************************************************************************************ -// -// ProgressDlgProc -// - -INT_PTR CALLBACK -ProgressDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - RemoveIconIfNoColors(hDlg); - PostMessage(hDlg, WM_USER_STARTINSTALL, 0, 0); - break; - } - - case WM_USER_STARTINSTALL: - { - HProgressDialog = hDlg; - UpdateWindow(hDlg); - if (!DoInstallation()) - { - char buff[1024]; - wsprintf(buff, LoadStr(IDS_INSTFAILED), SetupInfo.ApplicationName); - MessageBox(hDlg, buff, MAINWINDOW_TITLE, MB_OK | MB_ICONEXCLAMATION); - PostQuitMessage(0); - return 0; - } - PostMessage(HWizardDialog, WM_COMMAND, _TPD_IDC_NEXT, 0); - return 0; - } - - case WM_CTLCOLORSTATIC: - { - int childID = (int)(DWORD_PTR)GetMenu((HWND)lParam); - - if (childID == IDC_BOLDWHITE_TEXT) - SelectObject((HDC)wParam, HBoldFont); - - if (childID == IDC_WHITE_RECT || childID == IDC_BOLDWHITE_TEXT || childID == IDC_NORMALWHITE_TEXT) - return (INT_PTR)GetStockObject(WHITE_BRUSH); - break; - } - - case WM_NOTIFY: - { - NMHDR* hdr = (NMHDR*)lParam; - switch (hdr->code) - { - case PSN_SETACTIVE: - { - ShowWindow(GetDlgItem(HWizardDialog, _TPD_IDC_BACK), SW_HIDE); - ShowWindow(GetDlgItem(HWizardDialog, _TPD_IDC_NEXT), SW_HIDE); - // SetDlgItemText(HWizardDialog, _TPD_IDC_EXIT, LoadStr(IDS_WZR_FINISH)); - EnableWindow(GetDlgItem(HWizardDialog, _TPD_IDC_EXIT), FALSE); - - SendMessage(HWizardDialog, DM_SETDEFID, _TPD_IDC_EXIT, 0); - SendDlgItemMessage(HWizardDialog, _TPD_IDC_EXIT, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE); - SetFocus(GetDlgItem(HWizardDialog, _TPD_IDC_EXIT)); - break; - } - } - break; - } - } - return FALSE; -} - -void SetProgressMax(int max) -{ - if (SetupInfo.Silent) - return; - SendDlgItemMessage(HProgressDialog, IDC_PGS_PGS, PBM_SETRANGE, 0, MAKELPARAM(0, max)); - UpdateWindow(HProgressDialog); -} - -void SetProgressPos(int pos) -{ - if (SetupInfo.Silent) - return; - SendDlgItemMessage(HProgressDialog, IDC_PGS_PGS, PBM_SETPOS, pos, 0); - UpdateWindow(HProgressDialog); -} - -void SetFromTo(const char* from, const char* to) -{ - if (SetupInfo.Silent) - return; - - // "From" can be long because of the TEMP path and its end used to be clipped. - // Switch to smarter functions that can shorten the path correctly. - PathSetDlgItemPath(HProgressDialog, IDC_PGS_FROM, from); - PathSetDlgItemPath(HProgressDialog, IDC_PGS_TO, to); - //SendDlgItemMessage(HProgressDialog, IDC_PGS_FROM, WM_SETTEXT, 0, (LPARAM)from); - //SendDlgItemMessage(HProgressDialog, IDC_PGS_TO, WM_SETTEXT, 0, (LPARAM)to); -} - -//************************************************************************************ -// -// MyCreateProcess -// - -void MyCreateProcess(const char* fileName, BOOL parseCurDir, BOOL addQuotes) -{ - STARTUPINFO si = {0}; - PROCESS_INFORMATION pi; - char buf[MAX_PATH]; - char buf2[MAX_PATH + 2]; - - if (lstrlen(fileName) >= MAX_PATH) - return; - - if (parseCurDir) - { - char* p; - lstrcpy(buf, fileName); - p = buf + lstrlen(buf) - 1; - while (p > buf && *p != '\\') - p--; - if (p >= buf && *p == '\\') - *p = 0; - } - - if (addQuotes) - wsprintf(buf2, "\"%s\"", fileName); - else - lstrcpy(buf2, fileName); - si.cb = sizeof(STARTUPINFO); - CreateProcess(NULL, buf2, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, parseCurDir ? buf : NULL, &si, &pi); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); -} - -//************************************************************************************ -// -// DoneDlgProc -// - -typedef BOOL(WINAPI* FAllowSetForegroundWindow)(DWORD dwProcessId); - -INT_PTR CALLBACK -DoneDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - BOOL viewVisible; - BOOL runVisible; - RECT r; - - // pull the data out of the INF file - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_VIEWREADME, "", - SetupInfo.ViewReadmePath, MAX_PATH, InfFileName); - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_RUNPROGRAM, "", - SetupInfo.RunProgramPath, MAX_PATH, InfFileName); - GetPrivateProfileString(INF_PRIVATE_SECTION, INF_RUNPROGRAMQUIET, "", - SetupInfo.RunProgramQuietPath, MAX_PATH, InfFileName); - - ExpandPath(SetupInfo.ViewReadmePath); - ExpandPath(SetupInfo.RunProgramPath); - ExpandPath(SetupInfo.RunProgramQuietPath); - - viewVisible = SetupInfo.ViewReadmePath[0] != 0 && SfxDirectoriesValid; - runVisible = SetupInfo.RunProgramPath[0] != 0 && SfxDirectoriesValid; - - SetupInfo.RunProgramQuiet = SetupInfo.RunProgramQuietPath[0] != 0; - - ShowWindow(GetDlgItem(hDlg, IDC_DONE_README), viewVisible); - ShowWindow(GetDlgItem(hDlg, IDC_DONE_RUN), runVisible); - - InsertAppName(hDlg, IDC_DONE_TEXT, FALSE); - if (viewVisible || runVisible) - InsertAppName(hDlg, IDC_DONE_TEXT2, FALSE); - else - SetDlgItemText(hDlg, IDC_DONE_TEXT2, ""); - - if (viewVisible) - CheckDlgButton(hDlg, IDC_DONE_README, SetupInfo.ViewReadme ? BST_CHECKED : BST_UNCHECKED); - else - SetupInfo.ViewReadme = FALSE; - - if (runVisible) - { - InsertAppName(hDlg, IDC_DONE_RUN, FALSE); - CheckDlgButton(hDlg, IDC_DONE_RUN, SetupInfo.RunProgram ? BST_CHECKED : BST_UNCHECKED); - } - else - SetupInfo.RunProgram = FALSE; - - if (GetWindowRect(GetDlgItem(HWizardDialog, _TPD_IDC_EXIT), &r)) - { - POINT p; - p.x = r.left; - p.y = r.top; - ScreenToClient(HWizardDialog, &p); - MoveWindow(GetDlgItem(HWizardDialog, _TPD_IDC_NEXT), p.x, p.y, r.right - r.left, r.bottom - r.top, FALSE); - } - ShowWindow(GetDlgItem(HWizardDialog, _TPD_IDC_EXIT), SW_HIDE); - ShowWindow(GetDlgItem(HWizardDialog, _TPD_IDC_NEXT), SW_SHOW); - SetDlgItemText(HWizardDialog, _TPD_IDC_NEXT, LoadStr(IDS_WZR_FINISH)); - - SendMessage(HWizardDialog, DM_SETDEFID, _TPD_IDC_NEXT, 0); - SendDlgItemMessage(HWizardDialog, _TPD_IDC_NEXT, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE); - SetFocus(GetDlgItem(HWizardDialog, _TPD_IDC_NEXT)); - - break; - } - - case WM_CTLCOLORSTATIC: - { - if ((HWND)lParam == GetDlgItem(hDlg, IDC_WLC_A)) - SelectObject((HDC)wParam, HBoldFont); - return (INT_PTR)GetStockObject(WHITE_BRUSH); - } - - case WM_ERASEBKGND: - { - HDC hDC = (HDC)wParam; - RECT r; - GetClientRect(hDlg, &r); - FillRect(hDC, &r, (HBRUSH)(COLOR_WINDOW + 1)); - DrawLogoBitmap(hDC, r); - return TRUE; // background is erased - } - - case WM_COMMAND: - { - if (HIWORD(wParam) == BN_CLICKED) - { - SetupInfo.ViewReadme = IsDlgButtonChecked(hDlg, IDC_DONE_README) == BST_CHECKED; - SetupInfo.RunProgram = IsDlgButtonChecked(hDlg, IDC_DONE_RUN) == BST_CHECKED; - } - - switch (LOWORD(wParam)) - { - case IDOK: - { - // so the temp directory underneath us can be deleted - char buf[MAX_PATH]; - GetFolderPath(CSIDL_SYSTEM, buf); - SetCurrentDirectory(buf); // we must leave the directory; otherwise it cannot be deleted - - wsprintf(buf, "notepad.exe \"%s\"", SetupInfo.ViewReadmePath); - // Vista+: the SFX process runs unelevated; when elevating we may switch to the admin account and the programs would start under a different user - if (SfxDirectoriesValid) - { - StoreExecuteInfo(SetupInfo.ViewReadmePath, SetupInfo.RunProgramPath, - SetupInfo.ViewReadme, SetupInfo.RunProgram); - if (SfxDlg != NULL && (SetupInfo.ViewReadme || SetupInfo.RunProgram)) - { - DWORD sfxPID; - FAllowSetForegroundWindow allowSetForegroundWindow; - - GetWindowThreadProcessId(SfxDlg, &sfxPID); - // allow the activated process to call SetForegroundWindow; otherwise it would not be able to bring itself to the front - allowSetForegroundWindow = (FAllowSetForegroundWindow)GetProcAddress(GetModuleHandle("user32.dll"), "AllowSetForegroundWindow"); - if (allowSetForegroundWindow != NULL) - allowSetForegroundWindow(sfxPID); - // show and activate the SFX7ZIP dialog - SendMessage(SfxDlg, WM_USER_SHOWACTSFX7ZIP, 0, 0); - } - } - - PostQuitMessage(0); - break; - } - } - - break; - } - - case WM_TIMER: - { - if (wParam == WM_USER_CLOSEWIZARDDLG) - PostQuitMessage(0); // we can no longer delay closing the wizard dialog, so exit - break; - } - } - return FALSE; -} - -//************************************************************************************ -// -// WizardDlgProc -// - -INT_PTR CALLBACK -WizardDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - HDC hdc; - HFONT hFont; - LOGFONT lf; - char buff[500]; - HMENU hMenu; - HWND hwnd; - POINT p; - RECT separatorRect; - HWizardDialog = hDlg; - CenterWindow(hDlg); - hwnd = GetDlgItem(HWizardDialog, IDC_WIZARD_SEPARATOR); - GetClientRect(hDlg, &ChildDialogRect); - GetWindowRect(hwnd, &separatorRect); - p.x = separatorRect.right; - p.y = separatorRect.top; - ScreenToClient(HWizardDialog, &p); - ChildDialogRect.bottom = p.y; - - // assign an icon to the window - SendMessage(hDlg, WM_SETICON, ICON_BIG, - (LPARAM)LoadIcon(HInstance, MAKEINTRESOURCE(EXE_ICON))); - - // disable items in the system menu - hMenu = GetSystemMenu(hDlg, FALSE); - if (hMenu != NULL) - { - EnableMenuItem(hMenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(hMenu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED); - } - - // assign text to the window - wsprintf(buff, LoadStr(IDS_WIZ_TITLE), SetupInfo.ApplicationName); - SetWindowText(hDlg, buff); - - // create a bold font - hFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0); - GetObject(hFont, sizeof(lf), &lf); - lf.lfWeight = FW_BOLD; - HBoldFont = CreateFontIndirect(&lf); - - lf.lfWeight = FW_NORMAL; - lf.lfUnderline = TRUE; - HULFont = CreateFontIndirect(&lf); - - // if we run in 256 colors or fewer, do not show the symbol in the top-right corner - hdc = GetDC(hDlg); - RunningInLowColors = GetDeviceCaps(hdc, BITSPIXEL) <= 8; - ReleaseDC(hDlg, hdc); - - SelectPage(0); - break; - } - - case WM_CTLCOLORSTATIC: - { - if ((HWND)lParam == GetDlgItem(hDlg, IDC_WWW)) - { - SelectObject((HDC)wParam, HULFont); - SetTextColor((HDC)wParam, RGB(0, 0, 255)); - SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNFACE)); - return (INT_PTR)GetSysColorBrush(COLOR_BTNFACE); - } - break; - } - - case WM_LBUTTONDOWN: - case WM_SETCURSOR: - { - DWORD pos; - POINT p; - BOOL hit; - pos = GetMessagePos(); - p.x = GET_X_LPARAM(pos); - p.y = GET_Y_LPARAM(pos); - ScreenToClient(hDlg, &p); - - hit = ChildWindowFromPoint(hDlg, p) == GetDlgItem(hDlg, IDC_WWW); - if (hit) - { - if (uMsg == WM_LBUTTONDOWN) - { - ShellExecute(NULL, "open", "https://www.taskscape.com", NULL, NULL, 0); - } - else - { - SetCursor(LoadCursor(HInstance, MAKEINTRESOURCE(IDC_HANDICON))); - return TRUE; - } - } - break; - } - - case WM_ACTIVATE: - { - if (LOWORD(wParam) == WA_INACTIVE && CloseWizardDlgOnDeact) - PostQuitMessage(0); // they are already deactivating us; the wizard dialog is no longer needed, so exit - break; - } - - case WM_DESTROY: - { - if (HBoldFont != NULL) - { - DeleteObject(HBoldFont); - HBoldFont = NULL; - } - if (HULFont != NULL) - { - DeleteObject(HULFont); - HULFont = NULL; - } - break; - } - - case WM_SYSCOMMAND: - { - if (wParam == SC_CLOSE && !IsWindowVisible(GetDlgItem(HWizardDialog, _TPD_IDC_EXIT))) - { // clicking the window's close button or pressing Alt+F4 on the last page (Installation Finished): the user does not want to launch Salamander or open the readme, so exit - PostQuitMessage(0); - return TRUE; - } - break; - } - - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case ID_STOPINSTALL: - { - PostQuitMessage(0); - return 0; - } - - case _TPD_IDC_BACK: - { - NMHDR nmhdr; - LONG_PTR res; - HWND hPage = WizardPages[CurrentPageIndex].HWindow; - nmhdr.hwndFrom = HWizardDialog; - nmhdr.idFrom = 0; - nmhdr.code = PSN_KILLACTIVE; - SendMessage(hPage, WM_NOTIFY, 0, (LPARAM)&nmhdr); - res = GetWindowLongPtr(hPage, DWLP_MSGRESULT); - if (res != 0) - return TRUE; - - SelectPage(CurrentPageIndex - 1); - return TRUE; - } - - case _TPD_IDC_NEXT: - { - NMHDR nmhdr; - LONG_PTR res; - HWND hPage = WizardPages[CurrentPageIndex].HWindow; - nmhdr.hwndFrom = HWizardDialog; - nmhdr.idFrom = 0; - nmhdr.code = PSN_KILLACTIVE; - SendMessage(hPage, WM_NOTIFY, 1, (LPARAM)&nmhdr); - res = GetWindowLongPtr(hPage, DWLP_MSGRESULT); - if (res != 0) - return TRUE; - - if (CurrentPageIndex == PagesCount - 1) - PostMessage(hPage, WM_COMMAND, IDOK, 0); - else - SelectPage(CurrentPageIndex + 1); - return TRUE; - } - - case _TPD_IDC_EXIT: - { - if (CurrentPageIndex >= PagesCount || StopInstalling() == IDOK) - PostMessage(HWizardDialog, WM_COMMAND, ID_STOPINSTALL, 0); - return TRUE; - } - } - break; - } - } - return FALSE; -} - -//************************************************************************************ -// -// StopInstalling -// - -BOOL StopInstalling() -{ - int ret; - ret = MessageBox(HWizardDialog, LoadStr(IDS_INSTALL_STOP), - LoadStr(IDS_INSTALL_STOP_TITLE), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2); - return ret == IDYES; -} - -//************************************************************************************ -// -// AddWizardPage -// - -void AddWizardPage(int index, int dlgResID, DLGPROC pfnDlgProc) -{ - WizardPages[index].ResID = dlgResID; - WizardPages[index].DlgProc = pfnDlgProc; -} - -//************************************************************************************ -// -// EnableButtons -// - -void EnableButtons() -{ - if (CurrentPageIndex == 0) - { - ShowWindow(GetDlgItem(HWizardDialog, _TPD_IDC_BACK), FALSE); - SendDlgItemMessage(HWizardDialog, _TPD_IDC_NEXT, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE); - } - if (CurrentPageIndex == 1) - { - ShowWindow(GetDlgItem(HWizardDialog, _TPD_IDC_BACK), TRUE); - SendDlgItemMessage(HWizardDialog, _TPD_IDC_BACK, BM_SETSTYLE, BS_PUSHBUTTON, TRUE); - } -} - -//************************************************************************************ -// -// SelectPage -// - -BOOL SelectPage(int pageIndex) -{ - HWND hHideWindow; - NMHDR nmhdr; - - if (pageIndex < 0 || pageIndex >= PagesCount) - return FALSE; - hHideWindow = NULL; - if (HChildDialog != NULL) - { - hHideWindow = HChildDialog; - HChildDialog = NULL; - } - - if (pageIndex != CurrentPageIndex) - { - struct CWizardPage* page; - page = &WizardPages[pageIndex]; - if (page->HWindow == NULL) - { - page->HWindow = CreateDialog(HInstance, MAKEINTRESOURCE(page->ResID), - HWizardDialog, page->DlgProc); - nmhdr.hwndFrom = HWizardDialog; - nmhdr.idFrom = 0; - nmhdr.code = PSN_SETACTIVE; - SendMessage(page->HWindow, WM_NOTIFY, 0, (LPARAM)&nmhdr); - } - HChildDialog = page->HWindow; - - nmhdr.hwndFrom = HWizardDialog; - nmhdr.idFrom = 0; - nmhdr.code = PSN_SETACTIVE; - SendMessage(page->HWindow, WM_NOTIFY, 0, (LPARAM)&nmhdr); - - if (hHideWindow != NULL) - SetWindowPos(hHideWindow, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW | SWP_HIDEWINDOW); - - SetWindowPos(page->HWindow, HWND_TOP, - ChildDialogRect.left, ChildDialogRect.top, - ChildDialogRect.right - ChildDialogRect.left, - ChildDialogRect.bottom - ChildDialogRect.top, - SWP_SHOWWINDOW); - CurrentPageIndex = pageIndex; - EnableButtons(); - UpdateWindow(page->HWindow); - UpdateWindow(HWizardDialog); - } - return TRUE; -} - -//************************************************************************************ -// -// GetCurDispLangID -// - -typedef LANGID(WINAPI* FGetUserDefaultUILanguage)(); - -WORD GetCurDispLangID() -{ - WORD langID; - HMODULE KERNEL32DLL; - - langID = GetUserDefaultLangID(); - - // adjust the langID on newer Windows versions - KERNEL32DLL = LoadLibrary("kernel32.dll"); - if (KERNEL32DLL != NULL) - { - FGetUserDefaultUILanguage proc = (FGetUserDefaultUILanguage)GetProcAddress(KERNEL32DLL, "GetUserDefaultUILanguage"); - if (proc != NULL) - langID = proc(); - FreeLibrary(KERNEL32DLL); - } - - return langID; -} - -//************************************************************************************ -// -// CreateWizard -// - -BOOL CreateWizard() -{ - PagesCount = 0; - AddWizardPage(PagesCount++, IDD_WELCOME, WelcomeDlgProc); - if (SetupInfo.UseFirstReadme) - AddWizardPage(PagesCount++, IDD_README, ReadmeDlgProc); - if (SetupInfo.UseLicenseFile) - AddWizardPage(PagesCount++, IDD_LICENSE, LicenseDlgProc); - if (!SetupInfo.SkipChooseDir) - AddWizardPage(PagesCount++, IDD_DESTINATION, DestinationDlgProc); - if (SetupInfo.DesktopPresent | SetupInfo.StartMenuPresent) - AddWizardPage(PagesCount++, IDD_FOLDER, FolderDlgProc); - AddWizardPage(PagesCount++, IDD_FINISH, FinishDlgProc); - AddWizardPage(PagesCount++, IDD_UNINSTALL, UninstallDlgProc); - AddWizardPage(PagesCount++, IDD_PROGRESS, ProgressDlgProc); - AddWizardPage(PagesCount++, IDD_DONE, DoneDlgProc); - // !!!WARNING!!! increase NUM_PAGES if we add a page - - HWizardDialog = CreateDialog(HInstance, MAKEINTRESOURCE(IDD_WIZARD), NULL, WizardDlgProc); - if (HWizardDialog == NULL) - return FALSE; - ShowWindow(HWizardDialog, SW_SHOW); - - return TRUE; -} - -//************************************************************************************ -// -// InstallDone -// -/* -INT_PTR CALLBACK -FillFormDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - CenterWindow(hDlg); - break; - } - } - return FALSE; -} -*/ -BOOL MyGetMultilineText(char* srcData, char buff[100][MAX_PATH], int* lines) -{ - char line[10000]; - char* end; - char* p = srcData; - int index = 0; - - while (*p != '[' && *p != 0) - { - while (*p == '\r' || *p == '\n') - p++; - - end = p; - while (*end != '\r' && *end != '\n' && *end != 0) - end++; - - while (*p == ' ') - p++; - - lstrcpyn(line, p, (int)(end - p + 1)); - - if (*line != ';' && *line != 0) - { - int len; - if (index < 99) - lstrcpy(buff[index], line); - len = lstrlen(line); - index++; - } - while (*end == '\r' || *end == '\n') - end++; - p = end; - } - buff[index][0] = 0; - *lines = index; - return TRUE; -} - -char PreviousVerOfFileToIncrementContent[10000]; - -void ReadPreviousVerOfFileToIncrementContent() -{ - HANDLE hFile; - DWORD read; - char* end; - char fileName[MAX_PATH]; - - end = SetupInfo.IncrementFileContentDst; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(fileName, SetupInfo.IncrementFileContentDst, (int)(end - SetupInfo.IncrementFileContentDst + 1)); - ExpandPath(fileName); // let the path expand - if (fileName[0] == 0) - return; // failed to obtain even the file name - - // if the file exists, it will be opened; otherwise it will be created - hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return; - - if (ReadFile(hFile, PreviousVerOfFileToIncrementContent, 10000, &read, NULL) && read > 0) - PreviousVerOfFileToIncrementContent[read] = 0; - else - PreviousVerOfFileToIncrementContent[0] = 0; - - CloseHandle(hFile); -} - -BOOL IncrementFileContent() -{ - HANDLE hFile; - DWORD read; - char* begin; - char* end; - int index, i; - DWORD cfgVersion; - int ifcLinesCount = 0; - char ifcLines[100][MAX_PATH]; // unpack the IncrementFileContent entries here; - // the zeroth line will be the file name; the list ends - // with a line containing only the character 0 - int fileLinesCount = 0; - char fileLines[100][MAX_PATH]; // unpack lines from the existing file here - char fileBuff[10000]; - - DWORD registryVal; - - // first fetch the current number from the registry - if (!GetRegistryDWORDValue(SetupInfo.IncrementFileContentSrc, ®istryVal)) - { // the installed version has no registry entry (it has not run on this account yet) - if (!SetupInfo.UninstallExistingVersion || !SetupInfo.TheExistingVersionIsSame) - return FALSE; - registryVal = 0; - } - - begin = end = SetupInfo.IncrementFileContentDst; - index = 0; - - while (*begin != 0) - { - while (*end != 0 && *end != ',') - end++; - lstrcpyn(ifcLines[index], begin, (int)(end - begin + 1)); - ExpandPath(ifcLines[index]); // expand all paths - if (*end == ',') - end++; - begin = end; - index++; - } - ifcLinesCount = index; - ifcLines[index][0] = 0; - - if (index == 0) - return FALSE; // failed to obtain even the file name - - // if the file exists, it will be opened; otherwise it will be created - hFile = CreateFile(ifcLines[0], GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; - - // if the file exists, read and analyze its contents - fileLines[0][0] = 0; - if (PreviousVerOfFileToIncrementContent[0] != 0) // when reinstalling the same version of Salamander, reuse the contents of the recently uninstalled plugins.ver (e.g. newly installed plugins must be carried over into the new plugins.ver; otherwise launching Salamander from another account would not add them automatically because the config version is not increased—only increasing it triggers auto-installation of all plugins) - MyGetMultilineText(PreviousVerOfFileToIncrementContent, fileLines, &fileLinesCount); - else - { - if (ReadFile(hFile, fileBuff, 10000, &read, NULL) && read > 0) - { - fileBuff[read] = 0; - MyGetMultilineText(fileBuff, fileLines, &fileLinesCount); - } - } - - // if we are creating a new file, start it with value one - cfgVersion = 1; - - // if the file contained a number, increment it by one (installing plugins from another account and not running Salamander on this account leads to plugins.ver having a higher version number than the registry) - if (fileLinesCount > 0) - cfgVersion = MyStrToDWORD(fileLines[0]) + 1; - - // optionally use the registry value increased by one (we want Salamander to find and load the new version of plugins.ver on the next start) - if (registryVal + 1 > cfgVersion) - cfgVersion = registryVal + 1; - - wsprintf(fileBuff, "%d\r\n", cfgVersion); - - // write the new data into the file based on IncrementFileContent - SetFilePointer(hFile, 0, 0, FILE_BEGIN); - if (!WriteFile(hFile, fileBuff, lstrlen(fileBuff), &read, NULL) || read != (DWORD)lstrlen(fileBuff)) - { - DWORD error = GetLastError(); - wsprintf(fileBuff, LoadStr(ERROR_CF_WRITEFILE), ifcLines[0]); - HandleErrorM(IDS_MAINWINDOWTITLE, fileBuff, error); - SetEndOfFile(hFile); - CloseHandle(hFile); - return FALSE; - } - - for (index = 1; index < ifcLinesCount; index++) - { - wsprintf(fileBuff, "%d:%s\r\n", cfgVersion, ifcLines[index]); - if (!WriteFile(hFile, fileBuff, lstrlen(fileBuff), &read, NULL) || read != (DWORD)lstrlen(fileBuff)) - { - DWORD error = GetLastError(); - wsprintf(fileBuff, LoadStr(ERROR_CF_WRITEFILE), ifcLines[0]); - HandleErrorM(IDS_MAINWINDOWTITLE, fileBuff, error); - SetEndOfFile(hFile); - CloseHandle(hFile); - return FALSE; - } - } - - // scan the original file contents and add plugins that were not added now - for (i = 1; i < fileLinesCount; i++) // the first line is the overall number - skip it - { - char* p = fileLines[i]; - while (*p != ':' && *p != 0) - p++; - if (*p == ':') - { - p++; - if (*p != 0) - { - BOOL found; - found = FALSE; - for (index = 1; index < ifcLinesCount; index++) - { - if (StrICmp(p, ifcLines[index]) == 0) - { - found = TRUE; - break; - } - } - if (!found) - { - wsprintf(fileBuff, "%s\r\n", fileLines[i]); - if (!WriteFile(hFile, fileBuff, lstrlen(fileBuff), &read, NULL) || read != (DWORD)lstrlen(fileBuff)) - { - DWORD error = GetLastError(); - wsprintf(fileBuff, LoadStr(ERROR_CF_WRITEFILE), ifcLines[0]); - HandleErrorM(IDS_MAINWINDOWTITLE, fileBuff, error); - SetEndOfFile(hFile); - CloseHandle(hFile); - return FALSE; - } - } - } - } - } - - SetEndOfFile(hFile); - CloseHandle(hFile); - - return TRUE; -} diff --git a/src/setup/language.h b/src/setup/language.h deleted file mode 100644 index 03c17918..00000000 --- a/src/setup/language.h +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#define ENGLISH_VERSION -//#define CZECH_VERSION -//#define GERMAN_VERSION diff --git a/src/setup/manifest.xml b/src/setup/manifest.xml deleted file mode 100644 index 6ca6a901..00000000 --- a/src/setup/manifest.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - -Open Salamander Setup - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - \ No newline at end of file diff --git a/src/setup/precomp.c b/src/setup/precomp.c deleted file mode 100644 index 29172edc..00000000 --- a/src/setup/precomp.c +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "precomp.h" diff --git a/src/setup/precomp.h b/src/setup/precomp.h deleted file mode 100644 index 3ff1c375..00000000 --- a/src/setup/precomp.h +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include - -#include "lstrfix.h" -#include "remove\utils.h" diff --git a/src/setup/remove/ctxmenu.c b/src/setup/remove/ctxmenu.c deleted file mode 100644 index 15cf6a01..00000000 --- a/src/setup/remove/ctxmenu.c +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "precomp.h" - -extern int StrICmp(const char* s1, const char* s2); - -int SplitPathAndConvertToWideChar(const char* fname, wchar_t* out_path, int out_path_wchars, wchar_t* out_fname, int out_fname_wchars) -{ - char buff[2 * MAX_PATH]; - lstrcpy(buff, fname); - if (lstrlen(buff) > 0) - { - char* p = buff + lstrlen(buff) - 1; - while (p > buff && *p != '\\') - p--; - if (*p == '\\') - *p = 0; - MultiByteToWideChar(CP_ACP, 0, buff, -1, out_path, out_path_wchars); - MultiByteToWideChar(CP_ACP, 0, p + 1, -1, out_fname, out_fname_wchars); - } - return 0; -} - -BOOL InvokeCommand(IContextMenu* ctxMenu, int id, HWND hParent) -{ - CMINVOKECOMMANDINFO ci; - memset(&ci, 0, sizeof(ci)); - ci.cbSize = sizeof(ci); - ci.hwnd = hParent; - ci.lpVerb = MAKEINTRESOURCE(id); - ci.nShow = SW_SHOWNORMAL; - return (ctxMenu->lpVtbl->InvokeCommand(ctxMenu, &ci) == S_OK); -} - -BOOL FindAndInvokeCommand(IContextMenu* ctxMenu, HMENU hMenu, const char* cmdName, HWND hParent) -{ - BOOL ret = FALSE; - MENUITEMINFO mi = {0}; - char itemName[500] = {0}; - - int itemsCount = GetMenuItemCount(hMenu); - int i; - for (i = 0; i < itemsCount; i++) - { - memset(&mi, 0, sizeof(mi)); // necessary here - mi.cbSize = sizeof(mi); - mi.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID | MIIM_SUBMENU; - mi.dwTypeData = itemName; - mi.cch = 500; - if (GetMenuItemInfo(hMenu, i, TRUE, &mi)) - { - if (mi.hSubMenu == NULL && (mi.fType & MFT_SEPARATOR) == 0) // not a submenu and not a separator - { - char name[2000]; // deliberately use 2000 instead of 200; shell extensions sometimes write double the amount (idea: Unicode = 2 * "number of characters"), etc. - name[0] = 0; - if (ctxMenu->lpVtbl->GetCommandString(ctxMenu, mi.wID, GCS_VERB, NULL, name, 200) == NOERROR) - { - if (StrICmp(name, cmdName) == 0) - { - ret = InvokeCommand(ctxMenu, mi.wID, hParent); - break; - } - } - } - } - } - return ret; -} - -BOOL InvokeCmdFromContextMenuAux(HWND hWnd, const char* fileName, const char* cmdName) -{ - BOOL ret = FALSE; - HRESULT res; - ITEMIDLIST* folder = NULL; - ITEMIDLIST* file = NULL; - IShellFolder* shell = NULL; - IShellFolder* parent = NULL; - - CoCreateInstance(&CLSID_ShellDesktop, NULL, CLSCTX_INPROC, &IID_IShellFolder, &shell); - if (shell != NULL) - { - wchar_t wPath[MAX_PATH] = {0}; - wchar_t wFileName[MAX_PATH] = {0}; - SplitPathAndConvertToWideChar(fileName, wPath, sizeof(wPath) / sizeof(wchar_t), wFileName, sizeof(wFileName) / sizeof(wchar_t)); - res = shell->lpVtbl->ParseDisplayName(shell, NULL, NULL, wPath, NULL, &folder, NULL); - if (res == S_OK) - { - shell->lpVtbl->BindToObject(shell, folder, NULL, &IID_IShellFolder, &parent); - if (parent != NULL) - { - IContextMenu* ctxMenu = NULL; - res = parent->lpVtbl->ParseDisplayName(parent, NULL, NULL, wFileName, NULL, &file, NULL); - if (res == S_OK) - parent->lpVtbl->GetUIObjectOf(parent, NULL, 1, &file, &IID_IContextMenu, NULL, &ctxMenu); - parent->lpVtbl->Release(parent); - if (ctxMenu != NULL) - { - HMENU hMenu = CreatePopupMenu(); - if (hMenu != NULL) - { - ctxMenu->lpVtbl->QueryContextMenu(ctxMenu, hMenu, 0, 0, 0x7FFF, CMF_NORMAL); - ret = FindAndInvokeCommand(ctxMenu, hMenu, cmdName, hWnd); - ctxMenu->lpVtbl->Release(ctxMenu); - DestroyMenu(hMenu); - } - } - } - } - shell->lpVtbl->Release(shell); - } - if (folder != NULL) - CoTaskMemFree(folder); - if (file != NULL) - CoTaskMemFree(file); - return ret; -} - -BOOL InvokeCmdFromContextMenu(HWND hWnd, const char* fileName, const char* cmdName) -{ - BOOL ret; - __try - { - // we do not want setup/remove to crash because of shell extensions - ret = InvokeCmdFromContextMenuAux(hWnd, fileName, cmdName); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - ret = FALSE; - } - return ret; -} diff --git a/src/setup/remove/ctxmenu.h b/src/setup/remove/ctxmenu.h deleted file mode 100644 index 8b9dfbdb..00000000 --- a/src/setup/remove/ctxmenu.h +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -BOOL InvokeCmdFromContextMenu(HWND hwnd, const char* fileName, const char* cmdName); diff --git a/src/setup/remove/icon1.ico b/src/setup/remove/icon1.ico deleted file mode 100644 index 71e4ff4324569a96fa582ee4c6dc29883823c600..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 766 zcmZ{hJx;_h5QQgzwCSLtWjnaVQf$F-=q9P+0x9mcjC`APOP4E9Qf`+Nksfa*`{PAm z=h^<|jXky^Qn0Vr4`S{6M&yz63$>Tbvl;MD09#S) z7P8^L7Q>YjtE)iNDrSMGS4_;=@WLgrbBzoIcC zmVe~h0vRV3IQu0*bzv)5DvKZeh3Tfw^G~cvfoZv5YlkaT8+buy=rB);i5D<7#3!^l zI6Dp#pzkb47c-b2F$OX!{s-m{a|C_pxPvEPh~%mDguPe}^U=Z*D##47L>8<(BpCS~ z`Pgo^J3A9np7@PBFxqpt;oOXXJ*|QjrNKcq=qZuSOidzBx%is - - - -Taskscape Ltd Uninstall - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - \ No newline at end of file diff --git a/src/setup/remove/precomp.c b/src/setup/remove/precomp.c deleted file mode 100644 index 29172edc..00000000 --- a/src/setup/remove/precomp.c +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "precomp.h" diff --git a/src/setup/remove/precomp.h b/src/setup/remove/precomp.h deleted file mode 100644 index 3db8218b..00000000 --- a/src/setup/remove/precomp.h +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include - -#include "../common/lstrfix.h" diff --git a/src/setup/remove/process.c b/src/setup/remove/process.c deleted file mode 100644 index 801ed8d7..00000000 --- a/src/setup/remove/process.c +++ /dev/null @@ -1,444 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "precomp.h" - -#include "utils.h" -#include "process.h" - -BOOL SetDebugPrivilege(BOOL enable); - -//************************************************************************************ -// -// Global data -// - -char* ProcessCache = NULL; -int PCAllocated = 0; -int PCUsed = 0; - -#define PC_DELTA 10 // growth step used when reallocating the cached process list - -//************************************************************************************ -// -// EnumProcesses, FindProcess, FreeProcesses -// - -#define TH32CS_SNAPPROCESS 0x00000002 -#define TH32CS_SNAPMODULE 0x00000008 - -typedef struct tagPROCESSENTRY32 -{ - DWORD dwSize; - DWORD cntUsage; - DWORD th32ProcessID; // this process - DWORD th32DefaultHeapID; - DWORD th32ModuleID; // associated exe - DWORD cntThreads; - DWORD th32ParentProcessID; // this process's parent process - LONG pcPriClassBase; // Base priority of process's threads - DWORD dwFlags; - CHAR szExeFile[MAX_PATH]; // Path -} PROCESSENTRY32; -typedef PROCESSENTRY32* PPROCESSENTRY32; -typedef PROCESSENTRY32* LPPROCESSENTRY32; - -#define MAX_MODULE_NAME32 255 - -typedef struct tagMODULEENTRY32 -{ - DWORD dwSize; - DWORD th32ModuleID; // This module - DWORD th32ProcessID; // owning process - DWORD GlblcntUsage; // Global usage count on the module - DWORD ProccntUsage; // Module usage count in th32ProcessID's context - BYTE* modBaseAddr; // Base address of module in th32ProcessID's context - DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr - HMODULE hModule; // The hModule of this module in th32ProcessID's context - char szModule[MAX_MODULE_NAME32 + 1]; - char szExePath[MAX_PATH]; -} MODULEENTRY32; -typedef MODULEENTRY32* PMODULEENTRY32; -typedef MODULEENTRY32* LPMODULEENTRY32; - -typedef HANDLE(WINAPI* PFNCREATETOOLHELP32SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); -typedef BOOL(WINAPI* PFNPROCESS32FIRST)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); -typedef BOOL(WINAPI* PFNPROCESS32NEXT)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); -typedef BOOL(WINAPI* PFNMODULE32FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); -typedef BOOL(WINAPI* PFNMODULE32NEXT)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); - -static HMODULE hModKERNEL32 = NULL; -static PFNCREATETOOLHELP32SNAPSHOT CreateToolhelp32Snapshot = NULL; -static PFNPROCESS32FIRST Process32First = NULL; -static PFNPROCESS32NEXT Process32Next = NULL; -static PFNMODULE32FIRST Module32First = NULL; -static PFNMODULE32NEXT Module32Next = NULL; - -BOOL BindSnapshotFunctions() -{ - if (hModKERNEL32 == NULL) - { - hModKERNEL32 = GetModuleHandle("KERNEL32.DLL"); - CreateToolhelp32Snapshot = (PFNCREATETOOLHELP32SNAPSHOT)GetProcAddress(hModKERNEL32, "CreateToolhelp32Snapshot"); - Process32First = (PFNPROCESS32FIRST)GetProcAddress(hModKERNEL32, "Process32First"); - Process32Next = (PFNPROCESS32NEXT)GetProcAddress(hModKERNEL32, "Process32Next"); - Module32First = (PFNMODULE32FIRST)GetProcAddress(hModKERNEL32, "Module32First"); - Module32Next = (PFNMODULE32NEXT)GetProcAddress(hModKERNEL32, "Module32Next"); - } - return (CreateToolhelp32Snapshot != NULL && - Process32First != NULL && Process32Next != NULL && - Module32First != NULL && Module32Next != NULL); -} - -BOOL GetProcessModule(DWORD dwPID, const char* exeName, - LPMODULEENTRY32 lpMe32, DWORD cbMe32) -{ - BOOL bRet = FALSE; - BOOL bFound = FALSE; - HANDLE hModuleSnap = NULL; - MODULEENTRY32 me32 = {0}; - - // Take a snapshot of all modules in the specified process. - - hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID); - if (hModuleSnap == INVALID_HANDLE_VALUE) - return (FALSE); - - // Fill the size of the structure before using it. - - me32.dwSize = sizeof(MODULEENTRY32); - - // Walk the module list of the process, and find the module of - // interest. Then copy the information to the buffer pointed - // to by lpMe32 so that it can be returned to the caller. - - if (Module32First(hModuleSnap, &me32)) - { - do - { - if (StrICmp(me32.szModule, exeName) == 0) - { - mini_memcpy(lpMe32, &me32, cbMe32); - bFound = TRUE; - } - } while (!bFound && Module32Next(hModuleSnap, &me32)); - - bRet = bFound; // if this sets bRet to FALSE, dwModuleID - // no longer exists in specified process - } - else - bRet = FALSE; // could not walk module list - - // Do not forget to clean up the snapshot object. - - CloseHandle(hModuleSnap); - - return (bRet); -} - -BOOL AddProcess(const char* exeName) -{ - if (PCUsed == PCAllocated) - { - char* p = (char*)LocalReAlloc(ProcessCache, (PCAllocated + PC_DELTA) * MAX_PATH, - LMEM_MOVEABLE | LMEM_ZEROINIT); - if (p != NULL) - { - ProcessCache = p; - PCAllocated += PC_DELTA; - } - } - if (PCUsed < PCAllocated) - { - char shortName[MAX_PATH]; - // when conversion to short name fails, ignore item - if (GetShortPathName(exeName, shortName, MAX_PATH) != 0) - { - lstrcpyn(ProcessCache + PCUsed * MAX_PATH, shortName, MAX_PATH); - PCUsed++; - return TRUE; - } - } - return FALSE; -} - -BOOL EnumProcessesToolHelp32() -{ - HINSTANCE hSnapshot; - BOOL ret = FALSE; - DWORD id = 0; - - // bind function to kernel32.dll - if (!BindSnapshotFunctions()) - return FALSE; // not working under NT4, but who cares... - - SetDebugPrivilege(TRUE); - - // Take a snapshot of all processes in the system. - hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (hSnapshot != INVALID_HANDLE_VALUE) - { - PROCESSENTRY32 pe32; - MODULEENTRY32 me32; - BOOL ok; - pe32.dwSize = sizeof(PROCESSENTRY32); - ok = Process32First(hSnapshot, &pe32); - while (ok) - { - if (GetProcessModule(pe32.th32ProcessID, pe32.szExeFile, &me32, sizeof(me32))) - { - // found module, add it to the cache - AddProcess(me32.szExePath); - } - - pe32.dwSize = sizeof(pe32); - ok = Process32Next(hSnapshot, &pe32); - } - if (!ok && GetLastError() == ERROR_NO_MORE_FILES) - ret = TRUE; - CloseHandle(hSnapshot); - } - - SetDebugPrivilege(FALSE); - - return ret; -} - -BOOL FindProcess(const char* fileName) -{ - int i; - for (i = 0; i < PCUsed; i++) - { - const char* pName = ProcessCache + i * MAX_PATH; - if (StrICmp(fileName, pName) == 0) - return TRUE; - } - return FALSE; -} - -void FreeProcesses() -{ - if (ProcessCache != NULL) - { - LocalFree(ProcessCache); - ProcessCache = NULL; - } - PCAllocated = 0; - PCUsed = 0; -} - -//************************************************************************************ -// -// SetDebugPrivilege -// - -BOOL SetPrivilege( - HANDLE hToken, // token handle - LPCTSTR Privilege, // Privilege to enable/disable - BOOL bEnablePrivilege // TRUE to enable. FALSE to disable -) -{ - TOKEN_PRIVILEGES tp; - LUID luid; - TOKEN_PRIVILEGES tpPrevious; - DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); - - if (!LookupPrivilegeValue(NULL, Privilege, &luid)) - return FALSE; - - // - // first pass. get current privilege setting - // - tp.PrivilegeCount = 1; - tp.Privileges[0].Luid = luid; - tp.Privileges[0].Attributes = 0; - - AdjustTokenPrivileges( - hToken, - FALSE, - &tp, - sizeof(TOKEN_PRIVILEGES), - &tpPrevious, - &cbPrevious); - - if (GetLastError() != ERROR_SUCCESS) - return FALSE; - - // - // second pass. set privilege based on previous setting - // - tpPrevious.PrivilegeCount = 1; - tpPrevious.Privileges[0].Luid = luid; - - if (bEnablePrivilege) - { - tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); - } - else - { - tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & - tpPrevious.Privileges[0].Attributes); - } - - AdjustTokenPrivileges( - hToken, - FALSE, - &tpPrevious, - cbPrevious, - NULL, - NULL); - - if (GetLastError() != ERROR_SUCCESS) - return FALSE; - - return TRUE; -} - -BOOL SetDebugPrivilege(BOOL enable) -{ - HANDLE hToken; - - if (!OpenProcessToken( - GetCurrentProcess(), - TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, - &hToken)) - return FALSE; - - // enable SeDebugPrivilege - if (!SetPrivilege(hToken, SE_DEBUG_NAME, enable)) - { - // close token handle - CloseHandle(hToken); - - // indicate failure - return FALSE; - } - - CloseHandle(hToken); - return TRUE; -} - -//************************************************************************************ -// -// Populate the module list using PSAPI (works on all NT based windows) -// - -typedef BOOL(WINAPI* PFNENUMPROCESSES)(DWORD* lpidProcess, DWORD cb, DWORD* cbNeeded); -typedef BOOL(WINAPI* PFNENUMPROCESSMODULES)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded); -typedef DWORD(WINAPI* PFNGETMODULEFILENAMEEXA)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize); - -HMODULE hModPSAPI = NULL; -PFNENUMPROCESSES pfnEnumProcesses = NULL; -PFNENUMPROCESSMODULES pfnEnumProcessModules = NULL; -PFNGETMODULEFILENAMEEXA pfnGetModuleFileNameExA = NULL; - -BOOL EnumProcessesPSAPI() -{ - DWORD pidArray[1024]; - DWORD cbNeeded; - DWORD nProcesses; - unsigned i, j; - - // - // Hook up to the 3 functions in PSAPI.DLL dynamically. We can't - // just call the functions implicitly, since that would make this program - // require the presence of PSAPI.DLL - // - if (hModPSAPI == NULL) - hModPSAPI = LoadLibrary("PSAPI.DLL"); - - if (hModPSAPI == NULL) - return FALSE; - - pfnEnumProcesses = (PFNENUMPROCESSES)GetProcAddress(hModPSAPI, "EnumProcesses"); - pfnEnumProcessModules = (PFNENUMPROCESSMODULES)GetProcAddress(hModPSAPI, "EnumProcessModules"); - pfnGetModuleFileNameExA = (PFNGETMODULEFILENAMEEXA)GetProcAddress(hModPSAPI, "GetModuleFileNameExA"); - if (pfnEnumProcesses == NULL || pfnEnumProcessModules == NULL || pfnGetModuleFileNameExA == NULL) - return FALSE; - - // If we get to this point, we've successfully hooked up to the PSAPI APIs - - // EnumProcesses returns an array of process IDs - if (!pfnEnumProcesses(pidArray, sizeof(pidArray), &cbNeeded)) - return FALSE; - - nProcesses = cbNeeded / sizeof(DWORD); // Determine number of processes - - // Iterate through each process in the array - for (i = 0; i < nProcesses; i++) - { - HMODULE hModuleArray[1024]; - HANDLE hProcess; - DWORD pid = pidArray[i]; - DWORD nModules; - - // Using the process ID, open up a handle to the process - hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); - if (hProcess == NULL) - continue; - - // EnumProcessModules returns an array of HMODULEs for the process - if (!pfnEnumProcessModules(hProcess, hModuleArray, sizeof(hModuleArray), &cbNeeded)) - { - CloseHandle(hProcess); - continue; - } - - // Calculate number of modules in the process - nModules = cbNeeded / sizeof(hModuleArray[0]); - - // Iterate through each of the process's modules - for (j = 0; j < nModules; j++) - { - HMODULE hModule = hModuleArray[j]; - char szModuleName[MAX_PATH]; - - // GetModuleFileNameEx is like GetModuleFileName, but works - // in other process address spaces - pfnGetModuleFileNameExA(hProcess, hModule, szModuleName, sizeof(szModuleName)); - - if (j == 0) // First module is the EXE. Just add it to the map - { - //pidNameMap.Add( pid, szModuleName ); - AddProcess(szModuleName); - } - else // Not the first module. It's a DLL - { - } - } - CloseHandle(hProcess); // We're done with this process handle - } - return TRUE; -} - -//************************************************************************************ -// -// EnumProcesses -// - -BOOL EnumProcesses() -{ - BOOL ret; - - FreeProcesses(); - ProcessCache = (char*)LocalAlloc(LPTR, PC_DELTA * MAX_PATH); - if (ProcessCache == NULL) - return FALSE; - else - PCAllocated = PC_DELTA; - - ret = EnumProcessesToolHelp32(); // try ToolHelp32 method - if (!ret) - ret = EnumProcessesPSAPI(); // if fails, we try PSAPI - - return ret; -} - -// for VS2008 -void* memset(void* dest, int val, size_t len) -{ - register unsigned char* ptr = (unsigned char*)dest; - while (len-- > 0) - *ptr++ = val; - return dest; -} diff --git a/src/setup/remove/process.h b/src/setup/remove/process.h deleted file mode 100644 index eb8c203a..00000000 --- a/src/setup/remove/process.h +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -BOOL EnumProcesses(); // stores all running processes and their names -BOOL FindProcess(const char* fileName); // returns TRUE if a process with 'fileName' (full path) exists -void FreeProcesses(); // frees allocated buffers containing process names diff --git a/src/setup/remove/remove.c b/src/setup/remove/remove.c deleted file mode 100644 index 8a8ad69a..00000000 --- a/src/setup/remove/remove.c +++ /dev/null @@ -1,1865 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "precomp.h" -#include -#include - -#include "utils.h" -#include "process.h" -#include "resource.h" -#include "ctxmenu.h" - -#pragma comment(lib, "comctl32.lib") - -#ifdef INSIDE_SETUP -#include "..\infinst.h" -#endif //INSIDE_SETUP - -extern HINSTANCE HInstance; -extern char ModulePath[MAX_PATH]; - -char ModuleName[MAX_PATH] = {0}; -#ifndef INSIDE_SETUP -HINSTANCE HInstance = NULL; -char ModulePath[MAX_PATH] = {0}; -#endif //INSIDE_SETUP -char RemoveInfFileName[MAX_PATH] = {0}; -char RemoveAppName[1024] = {0}; -char RemoveRunProgramQuiet[1024] = {0}; -//char CheckRunningApps[1024] = {0}; -char RemoveWERLocalDumps[5000] = {0}; -char InfFileBuffer[500000] = {0}; - -BOOL QuietMode = FALSE; -BOOL InsideSetupMode = FALSE; -//BOOL InstallingSameVersion = FALSE; -HWND HParent = NULL; // when called as an EXE or from setup in silent mode, the parent is NULL; otherwise it is the setup dialog - -// uninstall scripts -char UnpinFromTaskbar[100000] = {0}; -char RemoveFiles[400000] = {0}; -char RemoveDirs[100000] = {0}; -char RemoveRegValues[100000] = {0}; -char RemoveRegKeys[100000] = {0}; -char RemoveShellExts[100000] = {0}; - -extern const char* INF_REMOVE_DELFILES; -extern const char* INF_REMOVE_DELREGKEYS; -extern const char* INF_REMOVE_DELSHELLEXTS; - -const char* INF_REMOVE_DELDIRS = "DelDirs"; -const char* INF_REMOVE_DELREGVALS = "DelRegValues"; -const char* INF_REMOVE_UNPINFROMTASKBAR = "UnpinFromTaskbar"; -const char* INF_REMOVE_DELFILES = "DelFiles"; -const char* INF_REMOVE_DELREGKEYS = "DelRegKeys"; -const char* INF_REMOVE_DELSHELLEXTS = "DelShellExts"; - -const char* INF_REMOVE_OPTIONS_SECTION = "Options"; -const char* INF_REMOVE_OPTIONS_APPNAME = "UninstallApplication"; -const char* INF_REMOVE_OPTIONS_RUNPROGRAMQUIET = "RunProgramQuiet"; -//const char *INF_OPTIONS_CHECKRUNNINGAPPS = "CheckRunningApps"; -const char* INF_REMOVE_OPTIONS_WERLOCALDUMPS = "UninstallWERLocalDumps"; - -#ifndef INSIDE_SETUP -const char* INF_REMOVE_FILENAME = "\\remove.rlg"; -#endif //INSIDE_SETUP - -const char* BATCH_FILE_BEGIN = "@echo off\r\n:Repeat\r\ndel \"%s\"\r\nif exist \"%s\" goto Repeat\r\n"; -const char* BATCH_FILE_DELDIR = "rmdir \"%s\"\r\n"; -const char* BATCH_FILE_DELFILE = "del \"%s\"\r\n"; - -static WCHAR* AllocWideFromUtf8(const char* src) -{ - if (src == NULL) - return NULL; - int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, NULL, 0); - if (len <= 0) - return NULL; - WCHAR* buf = (WCHAR*)malloc(len * sizeof(WCHAR)); - if (buf == NULL) - return NULL; - if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, buf, len) == 0) - { - free(buf); - return NULL; - } - return buf; -} - -static DWORD GetFileAttributesUtf8Local(const char* fileName) -{ - DWORD attrs = INVALID_FILE_ATTRIBUTES; - WCHAR* fileNameW = AllocWideFromUtf8(fileName); - if (fileNameW == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return attrs; - } - attrs = GetFileAttributesW(fileNameW); - free(fileNameW); - return attrs; -} - -static BOOL SetFileAttributesUtf8Local(const char* fileName, DWORD attrs) -{ - BOOL ok = FALSE; - WCHAR* fileNameW = AllocWideFromUtf8(fileName); - if (fileNameW == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - ok = SetFileAttributesW(fileNameW, attrs); - free(fileNameW); - return ok; -} - -static BOOL RemoveDirectoryUtf8Local(const char* dirName) -{ - BOOL ok = FALSE; - WCHAR* dirNameW = AllocWideFromUtf8(dirName); - if (dirNameW == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - ok = RemoveDirectoryW(dirNameW); - free(dirNameW); - return ok; -} - -typedef struct -{ - const char* AppName; - BOOL RemoveConfiguration; -} CConfirmationParams; - -CConfirmationParams ParamsGlobal; - -#ifndef INSIDE_SETUP -//************************************************************************************ -// -// LoadStr -// - -char* LoadStr(int resID) -{ - int size; - char* ret; - static char buffer[5000]; // buffer for many strings - static char* act = buffer; - - if (5000 - (act - buffer) < 200) - act = buffer; - size = LoadString(HInstance, resID, act, 5000 - (int)(act - buffer)); - if (size != 0 || GetLastError() == NO_ERROR) - { - ret = act; - act += size + 1; - } - else - { - ret = "ERROR LOADING STRING"; - } - - return ret; -} -#endif // INSIDE_SETUP - -char* GetErrorText(DWORD error) -{ - static char tempErrorText[MAX_PATH + 20]; - int l = wsprintf(tempErrorText, "(%d) ", error); - if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - tempErrorText + l, - MAX_PATH + 20 - l, - NULL) == 0 || - *(tempErrorText + l) == 0) - { - wsprintf(tempErrorText, "System error %d, text description is not available.", error); - } - return tempErrorText; -} - -//************************************************************************************ -// -// RemoveOnReboot -// - -BOOL RemoveOnReboot(LPCTSTR pszExisting /*, LPCTSTR pszNew*/) -{ - BOOL fOk = 0; - HMODULE hLib = LoadLibrary("kernel32.dll"); - if (hLib) - { - typedef BOOL(WINAPI * mfea_t)(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags); - mfea_t mfea; - mfea = (mfea_t)GetProcAddress(hLib, "MoveFileExA"); - if (mfea) - { - fOk = mfea(pszExisting, NULL /*pszNew*/, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING); - } - FreeLibrary(hLib); - } - - if (!fOk) - { - static char szRenameLine[1024]; - static char wininit[1024]; - static char tmpbuf[1024]; - int cchRenameLine; - char* szRenameSec = "[Rename]\r\n"; - HANDLE hfile, hfilemap; - DWORD dwFileSize, dwRenameLinePos; - - *((int*)tmpbuf) = *((int*)"NUL"); - - // if (pszNew) { - // // create the file if it's not already there to prevent GetShortPathName from failing - // CloseHandle(myOpenFile(pszNew, 0, CREATE_NEW)); - // GetShortPathName(pszNew,tmpbuf,1024); - // } - // wininit is used as a temporary here - GetShortPathName(pszExisting, wininit, 1024); - cchRenameLine = wsprintf(szRenameLine, "%s=%s\r\n", tmpbuf, wininit); - - GetFolderPath(CSIDL_WINDOWS, wininit); - lstrcat(wininit, "\\wininit.ini"); - hfile = CreateFile(wininit, - GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - - if (hfile != INVALID_HANDLE_VALUE) - { - dwFileSize = GetFileSize(hfile, NULL); - hfilemap = CreateFileMapping(hfile, NULL, PAGE_READWRITE, 0, dwFileSize + cchRenameLine + 10, NULL); - - if (hfilemap != NULL) - { - LPSTR pszWinInit = (LPSTR)MapViewOfFile(hfilemap, FILE_MAP_WRITE, 0, 0, 0); - - if (pszWinInit != NULL) - { - LPSTR pszRenameSecInFile = mystrstr(pszWinInit, szRenameSec); - if (pszRenameSecInFile == NULL) - { - lstrcpy(pszWinInit + dwFileSize, szRenameSec); - dwFileSize += 10; - dwRenameLinePos = dwFileSize; - } - else - { - char* pszFirstRenameLine = pszRenameSecInFile + 10; - char* pszNextSec = mystrstr(pszFirstRenameLine, "\n["); - if (pszNextSec) - { - int l = dwFileSize - (int)(pszNextSec - pszWinInit); - void* data = (void*)GlobalAlloc(GPTR, l); - mini_memcpy(data, pszNextSec, l); - mini_memcpy(pszNextSec + cchRenameLine, data, l); - GlobalFree((HGLOBAL)data); - - dwRenameLinePos = (int)(pszNextSec - pszWinInit); - } - // rename section is last, stick item at end of file - else - dwRenameLinePos = dwFileSize; - } - - mini_memcpy(&pszWinInit[dwRenameLinePos], szRenameLine, cchRenameLine); - dwFileSize += cchRenameLine; - - UnmapViewOfFile(pszWinInit); - - fOk++; - } - CloseHandle(hfilemap); - } - SetFilePointer(hfile, dwFileSize, NULL, FILE_BEGIN); - SetEndOfFile(hfile); - CloseHandle(hfile); - } - } - return fOk; -} - -//************************************************************************************ -// -// RemoveGetPrivateProfileSection -// - -BOOL RemoveGetPrivateProfileSection(const char* section, char* buff, int buffMax) -{ - char* p = InfFileBuffer; - char* dst = buff; - while (*p != 0) - { - while (*p != '[' && *p != 0) - p++; - if (*p == '[') - { - char* end = p + 1; - while (*end != ']' && *end != 0) - end++; - if (*end == ']') - { - char tmp[1024]; - char* src = p + 1; - lstrcpyn(tmp, src, (int)(end - src + 1)); - if (lstrcmpi(tmp, section) == 0) - { - char line[1024]; - p = end + 1; - - while (*p != '[' && *p != 0) - { - while (*p == '\r' || *p == '\n') - p++; - end = p; - while (*end != '\r' && *end != '\n' && *end != 0) - end++; - - while (*p == ' ') - p++; - - lstrcpyn(line, p, (int)(end - p + 1)); - - if (*line != ';' && *line != 0) - { - int len; - lstrcpy(dst, line); - len = lstrlen(line); - dst += len + 1; - } - while (*end == '\r' || *end == '\n') - end++; - p = end; - } - *dst = 0; - return TRUE; - } - else - { - p = end + 1; - } - } - else - return FALSE; - } - else - return FALSE; - } - return FALSE; -} - -#ifndef INSIDE_SETUP - -//************************************************************************************ -// -// CenterWindow -// - -void CenterWindow(HWND hWindow) -{ - RECT masterRect; - RECT slaveRect; - int x, y, w, h; - int mw, mh; - - masterRect.left = 0; - masterRect.top = 0; - masterRect.right = GetSystemMetrics(SM_CXSCREEN); - masterRect.bottom = GetSystemMetrics(SM_CYSCREEN); - - GetWindowRect(hWindow, &slaveRect); - w = slaveRect.right - slaveRect.left; - h = slaveRect.bottom - slaveRect.top; - mw = masterRect.right - masterRect.left; - mh = masterRect.bottom - masterRect.top; - x = masterRect.left + (mw - w) / 2; - y = masterRect.top + (mh - h) / 2; - SetWindowPos(hWindow, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); -} - -//************************************************************************************ -// -// strrchr -// - -char* strrchr(const char* string, int c) -{ - char* iter; - int len; - if (string == NULL) - return NULL; - len = lstrlen(string); - iter = (char*)string + len - 1; - while (iter >= string) - { - if (*iter == c) - return iter; - iter--; - } - return NULL; -} - -//************************************************************************************ -// -// GetCurDispLangID -// - -typedef LANGID(WINAPI* FGetUserDefaultUILanguage)(); - -WORD GetCurDispLangID() -{ - WORD langID; - HMODULE KERNEL32DLL; - - langID = GetUserDefaultLangID(); - - // adjust the langID on newer Windows versions - KERNEL32DLL = LoadLibrary("kernel32.dll"); - if (KERNEL32DLL != NULL) - { - FGetUserDefaultUILanguage proc = (FGetUserDefaultUILanguage)GetProcAddress(KERNEL32DLL, "GetUserDefaultUILanguage"); - if (proc != NULL) - langID = proc(); - FreeLibrary(KERNEL32DLL); - } - - return langID; -} - -typedef void(WINAPI* PGNSI)(LPSYSTEM_INFO); - -INT_PTR CALLBACK ConfirmationDlgProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - HICON hIcon; - char buff1[2 * MAX_PATH]; - char buff2[2 * MAX_PATH]; - - // center the dialog on the screen - CenterWindow(hWindow); - - hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_QUESTION)); - if (hIcon != NULL) - SendDlgItemMessage(hWindow, IDC_MYICON, STM_SETICON, (WPARAM)hIcon, 0); - - GetDlgItemText(hWindow, IDC_QUESTION, buff1, 2 * MAX_PATH); - wsprintf(buff2, buff1, ParamsGlobal.AppName); - SetDlgItemText(hWindow, IDC_QUESTION, buff2); - - CheckDlgButton(hWindow, IDC_REMOVECONFIGURATION, ParamsGlobal.RemoveConfiguration ? BST_CHECKED : BST_UNCHECKED); - - return TRUE; - } - - case WM_COMMAND: - { - switch (LOWORD(wParam)) - { - case IDYES: - { - ParamsGlobal.RemoveConfiguration = IsDlgButtonChecked(hWindow, IDC_REMOVECONFIGURATION) == BST_CHECKED; - } - case IDNO: - { - EndDialog(hWindow, LOWORD(wParam)); - return TRUE; - } - } - break; - } - } - return FALSE; -} - -#endif // INSIDE_SETUP - -//************************************************************************************ -// -// RemoveRemoveAllSubKeys -// - -BOOL RemoveRemoveAllSubKeys(HKEY hKey) -{ - char buff[MAX_PATH]; - while (RegEnumKey(hKey, 0, buff, MAX_PATH) != ERROR_NO_MORE_ITEMS) - { - HKEY hSubKey; - if (RegOpenKey(hKey, buff, &hSubKey) == ERROR_SUCCESS) - { - RemoveRemoveAllSubKeys(hSubKey); - RegCloseKey(hSubKey); - RegDeleteKey(hKey, buff); - } - } - return TRUE; -} - -//************************************************************************************ -// -// RemoveKey -// - -BOOL RemoveKey(HKEY hKey, const char* key) -{ - HKEY hSubKey; - if (RegOpenKey(hKey, key, &hSubKey) == ERROR_SUCCESS) - { - RemoveRemoveAllSubKeys(hSubKey); - RegCloseKey(hSubKey); - } - RegDeleteKey(hKey, key); - return TRUE; -} - -//************************************************************************************ -// -// RemoveOpenInfFile -// - -BOOL RemoveOpenInfFile() -{ - int ret; - - // load the basic data - ret = GetPrivateProfileString(INF_REMOVE_OPTIONS_SECTION, INF_REMOVE_OPTIONS_APPNAME, "", - RemoveAppName, 1024, RemoveInfFileName); - - if (ret == 0) - return FALSE; - - GetPrivateProfileString(INF_REMOVE_OPTIONS_SECTION, INF_REMOVE_OPTIONS_RUNPROGRAMQUIET, "", - RemoveRunProgramQuiet, 1024, RemoveInfFileName); - - // GetPrivateProfileString(INF_REMOVE_OPTIONS_SECTION, INF_REMOVE_OPTIONS_CHECKRUNNINGAPPS, "", - // CheckRunningApps, 1024, RemoveInfFileName); - - GetPrivateProfileString(INF_REMOVE_OPTIONS_SECTION, INF_REMOVE_OPTIONS_WERLOCALDUMPS, "", - RemoveWERLocalDumps, sizeof(RemoveWERLocalDumps), RemoveInfFileName); - - return TRUE; -} - -//************************************************************************************ -// -// ExistFiles -// - -BOOL ExistFiles(const char* files) -{ - const char* line; - - line = files; - while (*line != 0) - { - int len = lstrlen(line); - if (GetFileAttributesUtf8Local(line) != INVALID_FILE_ATTRIBUTES) - return TRUE; - line += len + 1; - } - return FALSE; -} - -//************************************************************************************ -// -// DoUnpinFromTaskbar -// - -BOOL DoUnpinFromTaskbar(const char* unpinFiles) -{ - const char* line; - line = unpinFiles; - while (*line != 0) - { - int len = lstrlen(line); - InvokeCmdFromContextMenu(HParent, line, "taskbarunpin"); - line += len + 1; - } - - return TRUE; -} - -//************************************************************************************ -// -// DoRemoveFiles -// - -BOOL DoRemoveFiles(const char* removeFiles) -{ - const char* line; - char buff[2 * MAX_PATH]; - int ret; - DWORD err; - - line = removeFiles; - while (*line != 0) - { - int len = lstrlen(line); - AGAIN: - SetFileAttributesUtf8Local(line, FILE_ATTRIBUTE_ARCHIVE); - if (!DeleteFile(line)) - { - err = GetLastError(); - // skip already deleted/nonexisting files - if (err != ERROR_PATH_NOT_FOUND && err != ERROR_FILE_NOT_FOUND) - { -#ifdef INSIDE_SETUP - if (SetupInfo.Silent) - return FALSE; -#endif //INSIDE_SETUP - wsprintf(buff, LoadStr(IDS_REMOVE_DELETEFAILED), line, GetErrorText(err)); - ret = MessageBox(HParent, buff, LoadStr(IDS_REMOVE_TITLE), MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | MB_DEFBUTTON2); - if (ret == IDABORT) - return FALSE; - if (ret == IDRETRY) - goto AGAIN; - } - } - line += len + 1; - } - - return TRUE; -} - -//************************************************************************************ -// -// DoRemoveDirs -// - -// we must be able to delete in a random order, so keep deleting while it succeeds - -BOOL DoRemoveDirs() -{ - BOOL someDirDeleted; - char* line; - - do - { - someDirDeleted = FALSE; - line = RemoveDirs; - while (*line != 0) - { - int len = lstrlen(line); - SetFileAttributesUtf8Local(line, FILE_ATTRIBUTE_ARCHIVE); - if (RemoveDirectoryUtf8Local(line)) - someDirDeleted = TRUE; - line += len + 1; - } - } while (someDirDeleted); - - return TRUE; -} - -//************************************************************************************ -// -// GetRootHandle -// - -HKEY RemoveGetRootHandle(const char* root) -{ - if (lstrcmpi(root, "HKLM") == 0) - return HKEY_LOCAL_MACHINE; - if (lstrcmpi(root, "HKCU") == 0) - return HKEY_CURRENT_USER; - if (lstrcmpi(root, "HKCC") == 0) - return HKEY_CURRENT_CONFIG; - if (lstrcmpi(root, "HKCR") == 0) - return HKEY_CLASSES_ROOT; - return NULL; -} - -//************************************************************************************ -// -// DoRemoveRegValues -// - -BOOL DoRemoveRegValues() -{ - char* line; - char root[MAX_PATH]; - char key[MAX_PATH]; - char valueName[MAX_PATH]; - BOOL ret; - - // MessageBox(HParent, "begin", "remove values", MB_OK); - line = RemoveRegValues; - while (*line != 0) - { - char* begin; - char* end; - HKEY hRoot; - HKEY hKey; - - int len = lstrlen(line); - - root[0] = 0; - key[0] = 0; - valueName[0] = 0; - - begin = end = line; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(valueName, begin, (int)(end - begin + 1)); - - hRoot = RemoveGetRootHandle(root); - - // MessageBox(HParent, key, "open key", MB_OK); - ret = RegOpenKeyEx(hRoot, key, 0, KEY_ALL_ACCESS, &hKey); - if (ret == ERROR_SUCCESS) - { - // MessageBox(HParent, valueName, "delete value", MB_OK); - RegDeleteValue(hKey, valueName); - RegCloseKey(hKey); - } - - line += len + 1; - } - - return TRUE; -} - -//************************************************************************************ -// -// DoRemoveRegKeys -// - -#ifdef INSIDE_SETUP -BOOL CreateAutoImportConfigMarker(const char* autoImportConfig, const char* autoImportConfigValue) -{ - if (autoImportConfig != NULL && autoImportConfig[0] != 0) - { - char root[MAX_PATH]; - char key[MAX_PATH]; - char value[MAX_PATH]; - - const char* begin; - const char* end; - HKEY hRoot; - HKEY hKey; - - int len = lstrlen(autoImportConfig); - - root[0] = 0; - key[0] = 0; - - begin = end = autoImportConfig; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(value, begin, (int)(end - begin + 1)); - - hRoot = RemoveGetRootHandle(root); - if (RegCreateKey(hRoot, key, &hKey) == ERROR_SUCCESS) - { - DWORD dwType = REG_SZ; - if (RegSetValueEx(hKey, (const char*)value, 0, dwType, autoImportConfigValue, lstrlen(autoImportConfigValue)) != ERROR_SUCCESS) - { - RegCloseKey(hKey); - return FALSE; - } - RegCloseKey(hKey); - } - } - return TRUE; -} - -BOOL IsRegistryKeyEmpty(HKEY hKey) -{ - char buff[MAX_PATH]; - if (RegEnumKey(hKey, 0, buff, MAX_PATH) != ERROR_NO_MORE_ITEMS) - return FALSE; - return TRUE; -} -BOOL DeleteAutoImportConfigMarker(const char* autoImportConfig) -{ - if (autoImportConfig != NULL && autoImportConfig[0] != 0) - { - char root[MAX_PATH]; - char key[MAX_PATH]; - char value[MAX_PATH]; - - const char* begin; - const char* end; - HKEY hRoot; - HKEY hKey; - - int len = lstrlen(autoImportConfig); - - root[0] = 0; - key[0] = 0; - - begin = end = autoImportConfig; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(value, begin, (int)(end - begin + 1)); - - hRoot = RemoveGetRootHandle(root); - - if (RegOpenKeyEx(hRoot, key, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) - { - BOOL deleteKey; - - // delete the value - RegDeleteValue(hKey, value); - - // if the key is empty after deleting the value, delete the key as well - deleteKey = IsRegistryKeyEmpty(hKey); - RegCloseKey(hKey); - - if (deleteKey) - { - char* end2; - end2 = key + lstrlen(key) - 1; - while ((end2 > key) && (*end2 != '\\')) - end2--; - if (end2 > key) - { - *end2 = 0; - lstrcpy(value, end2 + 1); - if (RegOpenKeyEx(hRoot, key, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) - { - // delete the key - RegDeleteKey(hKey, value); // under Win9x this removes subkeys too (see old MSDN), hence the check that the key is truly empty - RegCloseKey(hKey); - } - } - } - } - } - return TRUE; -} -#endif //INSIDE_SETUP - -BOOL ContainSubStrIgnoreCase(const char* str, const char* subStr) -{ - int len = lstrlen(subStr); - // if it is shorter than the substring, bail out - if (lstrlen(str) < len) - return FALSE; - - if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, str, len, subStr, len) == CSTR_EQUAL) - return TRUE; - - return FALSE; -} - -BOOL DoRemoveRegKeys(BOOL removeConfiguration) -{ - char* line; - char root[MAX_PATH]; - char key[MAX_PATH]; - char tmp[MAX_PATH]; - const char* UNINSTALL_KEY = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; - const char* SALAMNDER_KEY_NEW = "Software\\Taskscape Ltd\\Open Salamander"; - const char* SALAMNDER_KEY_OLD = "Software\\Taskscape Ltd\\Servant Salamander"; - - line = RemoveRegKeys; - while (*line != 0) - { - BOOL removeIt; - char* begin; - char* end; - HKEY hRoot; - - int len = lstrlen(line); - - root[0] = 0; - key[0] = 0; - - begin = end = line; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(root, begin, (int)(end - begin + 1)); - if (*end == ',') - end++; - - begin = end; - while (*end != 0 && *end != ',') - end++; - lstrcpyn(key, begin, (int)(end - begin + 1)); - - removeIt = removeConfiguration; - lstrcpy(tmp, key); - tmp[lstrlen(UNINSTALL_KEY)] = 0; // we do not have strstr, so work around it - if (lstrcmpi(tmp, UNINSTALL_KEY) == 0) // always cut off the uninstall record - removeIt = TRUE; - - hRoot = RemoveGetRootHandle(root); - if (removeIt) - { - RemoveKey(hRoot, key); - } - -#ifdef INSIDE_SETUP - if (!SetupInfo.TheExistingVersionIsSame) - { - if (ContainSubStrIgnoreCase(key, SALAMNDER_KEY_NEW) || ContainSubStrIgnoreCase(key, SALAMNDER_KEY_OLD)) - { - // store only the last component of the path - end = key + lstrlen(key) - 1; - while (end > key && *end != '\\') - end--; - if (end > key) - CreateAutoImportConfigMarker(SetupInfo.AutoImportConfig, end + 1); - } - } -#endif //INSIDE_SETUP - - line += len + 1; - } - - return TRUE; -} - -//************************************************************************************ -// -// DoRemoveWERLocalDumps -// - -int MyGetEXENameLen(const char* buff) -{ - const char* p = buff; - while (*p != 0 && *p != ',') - p++; - return (int)(p - buff); -} - -BOOL RemoveIsWow64() -{ - typedef BOOL(WINAPI * LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); - LPFN_ISWOW64PROCESS fnIsWow64Process; - BOOL bIsWow64 = FALSE; - //IsWow64Process is not available on all supported versions of Windows. - //Use GetModuleHandle to get a handle to the DLL that contains the function - //and GetProcAddress to get a pointer to the function if available. - fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process"); - if (NULL != fnIsWow64Process) - { - if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) - { - //handle error - } - } - return bIsWow64; -} - -void DoRemoveWERLocalDump(const char* exeName) -{ - // If an x86 application crashes on x64 Windows, WER uses entries from the x64 registry. - // The HKEY_LOCAL_MACHINE\SOFTWARE key is subject to the registry redirector, so the x86 Setup sees the x86 view, - // while the x64 Setup sees the x64 view. From the x86 Setup.exe we need to write to the x64 branch of the - // registry, which can be achieved using the special KEY_WOW64_64KEY flag, see MSDN: - // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129%28v=vs.85%29.aspx - // Note that bypassing the redirector also applies to doinst.c! - HKEY hKey; - DWORD taskscapeRefCount = 0xffffffff; - BOOL delExeKey = FALSE; - REGSAM samDesired = 0; - if (RemoveIsWow64()) - samDesired = KEY_WOW64_64KEY; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps", 0, samDesired | KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS) - { - HKEY hExeKey; - // open the key named after the EXE - if (RegOpenKeyEx(hKey, exeName, 0, samDesired | KEY_READ | KEY_WRITE, &hExeKey) == ERROR_SUCCESS) - { - DWORD dwType; - DWORD size = sizeof(taskscapeRefCount); - const char* dumpFolder = "%LOCALAPPDATA%\\Taskscape Ltd\\Open Salamander"; - dwType = REG_DWORD; - if (RegQueryValueEx(hExeKey, "TaskscapeLtdRefCount", 0, &dwType, (BYTE*)&taskscapeRefCount, &size) == ERROR_SUCCESS && dwType == REG_DWORD) - { - if (taskscapeRefCount != 0xffffffff && taskscapeRefCount > 0) - taskscapeRefCount--; - if (taskscapeRefCount == 0) - { - // delete the entire key after closing it - delExeKey = TRUE; - } - else - { - // store the new RefCount - dwType = REG_DWORD; - RegSetValueEx(hExeKey, "TaskscapeLtdRefCount", 0, dwType, (const BYTE*)&taskscapeRefCount, sizeof(taskscapeRefCount)); - } - } - RegCloseKey(hExeKey); - if (delExeKey) - RemoveKey(hKey, exeName); - } - RegCloseKey(hKey); - } -} - -void DoRemoveWERLocalDumps() -{ - char exeName[MAX_PATH]; - const char* names = RemoveWERLocalDumps; - while (*names != 0) - { - int exeNameLen = MyGetEXENameLen(names); - if (exeNameLen > 0 && exeNameLen < MAX_PATH - 1) - { - lstrcpyn(exeName, names, exeNameLen + 1); - DoRemoveWERLocalDump(exeName); - } - names += exeNameLen; - if (*names == ',') - names++; - } -} - -//************************************************************************************ -// -// DoRemoveShellExts -// -/* removing via CLSID is no longer necessary; now we go by file name -BOOL MyGetValue(HKEY hKey, const char *name, DWORD type, void *buffer, DWORD bufferSize) -{ - DWORD gettedType; - LONG res = RegQueryValueEx(hKey, name, 0, &gettedType, (BYTE *)buffer, &bufferSize); - return res == ERROR_SUCCESS && gettedType == type; -} - -typedef HRESULT (STDAPICALLTYPE *DLLUNREGPROC)() ; - -BOOL -RemoveShellExt(const char *clsid) -{ - HKEY hKey; - char key[MAX_PATH]; - char shellExtPath[MAX_PATH]; - BOOL registered; - DWORD attrs; - - // find out whether the shell extension is registered and how the SALSHEXT.DLL is named in TEMP - registered = FALSE; - lstrcpy(key, "CLSID\\"); - lstrcat(key, clsid); - lstrcat(key, "\\InProcServer32"); - if (RegOpenKeyEx(HKEY_CLASSES_ROOT, key, 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - if (MyGetValue(hKey, NULL, REG_SZ, shellExtPath, MAX_PATH)) - registered = TRUE; - RegCloseKey(hKey); - } - - // it appears to be registered - if (registered) - { - // try to load it and call the unregister function - HMODULE hShellExt = LoadLibrary(shellExtPath); - if (hShellExt != NULL) - { - DLLUNREGPROC DllUnregisterServer = (DLLUNREGPROC)GetProcAddress(hShellExt, "DllUnregisterServer"); - if (DllUnregisterServer != NULL) - DllUnregisterServer(); - FreeLibrary(hShellExt); - } - - // check whether the DLL exists and delete it - attrs = GetFileAttributesUtf8Local(shellExtPath); - if (attrs != INVALID_FILE_ATTRIBUTES) - { - if (attrs & FILE_ATTRIBUTE_READONLY) - SetFileAttributesUtf8Local(shellExtPath, attrs ^ FILE_ATTRIBUTE_READONLY); - // if it cannot be deleted normally, remove it after restart - if (!DeleteFile(shellExtPath)) - { - RemoveOnReboot(shellExtPath); - } - } - } - - return TRUE; -} -*/ - -typedef HRESULT(STDAPICALLTYPE* DLLUNREGPROC)(); - -BOOL TryToRenameShellExt(char* name) -{ - char buff[MAX_PATH]; - char ext[MAX_PATH]; - char* p; - int counter; - BOOL exist; - - if (lstrlen(name) > MAX_PATH - 10) - return FALSE; // nowhere to fit our number - - lstrcpy(buff, name); - - p = strrchr(buff, '.'); - if (p == NULL) - return FALSE; // shell extension without an extension? strange - - lstrcpy(ext, p); // backup of the extension - counter = 1; - do - { - wsprintf(p, "_%d%s", counter, ext); - exist = GetFileAttributesUtf8Local(buff) != INVALID_FILE_ATTRIBUTES; - if (exist) - counter++; - } while (exist && counter < 1000); - - if (exist) - return FALSE; // 1000 attempts must be enough; give up - - if (!MoveFile(name, buff)) - return FALSE; // on Win9x the rename may fail - - lstrcpy(name, buff); - return TRUE; -} - -BOOL RemoveShellExt(const char* shellExtPath, BOOL* delayedDelete, BOOL* renamingFailed) -{ - DWORD attrs; - - // try to load it and call the unregister function - HMODULE hShellExt = LoadLibrary(shellExtPath); - if (hShellExt != NULL) - { - DLLUNREGPROC DllUnregisterServer = (DLLUNREGPROC)GetProcAddress(hShellExt, "DllUnregisterServer"); - if (DllUnregisterServer != NULL) - DllUnregisterServer(); - DllUnregisterServer = (DLLUNREGPROC)GetProcAddress(hShellExt, "DllUnregisterServerOtherPlatform"); - if (DllUnregisterServer != NULL) - DllUnregisterServer(); - FreeLibrary(hShellExt); - } - - // check whether the DLL exists and delete it - attrs = GetFileAttributesUtf8Local(shellExtPath); - if (attrs != INVALID_FILE_ATTRIBUTES) - { - // drop the read-only attribute if it is set - if (attrs & FILE_ATTRIBUTE_READONLY) - SetFileAttributesUtf8Local(shellExtPath, attrs ^ FILE_ATTRIBUTE_READONLY); - - if (attrs & FILE_ATTRIBUTE_DIRECTORY) - { - if (*delayedDelete) - RemoveOnReboot(shellExtPath); - else - RemoveDirectoryUtf8Local(shellExtPath); - } - else - { - char newName[MAX_PATH]; - lstrcpyn(newName, shellExtPath, MAX_PATH); - newName[MAX_PATH - 1] = 0; - - if (!DeleteFile(newName)) - { - // try to rename the shell extension so that if the user immediately copies a new version of Salamander into the same directory after uninstalling, - // we do not accidentally cut off their new shell extension - if (!TryToRenameShellExt(newName)) - *renamingFailed = TRUE; - - // if it cannot be deleted normally, remove it after restart - RemoveOnReboot(newName); - *delayedDelete = TRUE; - } - } - } - - return TRUE; -} - -BOOL DoRemoveShellExts() -{ - BOOL delayedDelete = FALSE; - BOOL renamingFailed = FALSE; - char* line; - line = RemoveShellExts; - while (*line != 0) - { - int len = lstrlen(line); - RemoveShellExt(line, &delayedDelete, &renamingFailed); - line += len + 1; - } - if (renamingFailed) - return FALSE; - else - return TRUE; -} - -//************************************************************************************ -// -// CheckRunningApp -// -// checks whether an application with the window class appWindowClassName is running -// -/* -BOOL -CheckRunningApp(const char *appWindowClassName) -{ - HWND hWnd; - BOOL again; - do - { - again = FALSE; - hWnd = FindWindow(appWindowClassName, NULL); - if (hWnd != NULL) - { - HANDLE hProc; - DWORD dwID; - DWORD ret; - char windowName[100]; - char buff[2000]; - - GetWindowText(hWnd, windowName, 100); - wsprintf(buff, LoadStr(IDS_APPRUNNING), windowName); - - GetWindowThreadProcessId(hWnd, &dwID); - hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, dwID); - do - { -#ifdef INSIDE_SETUP - if (SetupInfo.Silent) return FALSE; -#endif //INSIDE_SETUP - int ret = MessageBox(HParent, buff, LoadStr(IDS_TITLE), MB_OKCANCEL | MB_ICONINFORMATION); - if (ret == IDCANCEL) - return FALSE; - } while (hProc != NULL && (ret = WaitForSingleObject(hProc, 10)) == WAIT_TIMEOUT); - } - } while (hWnd != NULL); - return TRUE; -} -*/ -//************************************************************************************ -// -// DoRemove -// - -// returns: TRUE for continue uninstall, FALSE for abort uninstall -BOOL LookupForRunningApps(const char* apps) -{ - const char* line = apps; - EnumProcesses(); - while (*line != 0) - { - char shortName[MAX_PATH]; - int len = lstrlen(line); - - // when conversion to short name fails, ignore item - if (GetShortPathName(line, shortName, MAX_PATH) != 0) - { - BOOL again; - do - { - again = FALSE; - if (FindProcess(shortName)) - { - char buff[2 * MAX_PATH]; - int ret; -#ifdef INSIDE_SETUP - if (SetupInfo.Silent) - return FALSE; -#endif //INSIDE_SETUP - wsprintf(buff, LoadStr(IDS_REMOVE_APPRUNNING), line); - ret = MessageBox(HParent, buff, LoadStr(IDS_REMOVE_TITLE), MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | MB_DEFBUTTON2); - - if (ret == IDABORT) - return FALSE; - - if (ret == IDRETRY) - { - EnumProcesses(); - again = TRUE; - } - } - } while (again); - } - - line += len + 1; - } - - return TRUE; -} - -BOOL DoRemove(BOOL* needRestart) -{ - HANDLE hFile; - DWORD read; - - if (needRestart != NULL) - *needRestart = FALSE; - - // load the INF file - hFile = CreateFile(RemoveInfFileName, GENERIC_READ, 0, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; - - if (!ReadFile(hFile, InfFileBuffer, 100000, &read, NULL)) - { - CloseHandle(hFile); - return FALSE; - } - CloseHandle(hFile); - - /* - if (CheckRunningApps[0] != 0) - { - // force the user to close applications from the list - char appClass[1000]; - char *begin; - char *end; - begin = end = CheckRunningApps; - while(*begin != 0) - { - while (*end != 0 && *end != ',') - end++; - lstrcpyn(appClass, begin, end - begin + 1); - if (*end == ',') - end++; - begin = end; - - if (!CheckRunningApp(appClass)) - return FALSE; // user canceled - } - } -*/ - - // load the lists slated for removal - RemoveGetPrivateProfileSection(INF_REMOVE_UNPINFROMTASKBAR, UnpinFromTaskbar, sizeof(UnpinFromTaskbar)); - RemoveGetPrivateProfileSection(INF_REMOVE_DELFILES, RemoveFiles, sizeof(RemoveFiles)); - RemoveGetPrivateProfileSection(INF_REMOVE_DELDIRS, RemoveDirs, sizeof(RemoveDirs)); - RemoveGetPrivateProfileSection(INF_REMOVE_DELREGVALS, RemoveRegValues, sizeof(RemoveRegValues)); - RemoveGetPrivateProfileSection(INF_REMOVE_DELREGKEYS, RemoveRegKeys, sizeof(RemoveRegKeys)); - RemoveGetPrivateProfileSection(INF_REMOVE_DELSHELLEXTS, RemoveShellExts, sizeof(RemoveShellExts)); - - ParamsGlobal.AppName = RemoveAppName; - ParamsGlobal.RemoveConfiguration = FALSE; // default values can be set here (if called in "InsideSetupMode", it must be FALSE!) - -#ifndef INSIDE_SETUP - if (!QuietMode && !InsideSetupMode) - { - // do we really want to terminate the application? - INT_PTR ret = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CONFIRMATION), - HParent, ConfirmationDlgProc, (LPARAM)NULL); - if (ret == IDNO) - return FALSE; // cancel - } -#endif // INSIDE_SETUP - - if (RemoveRunProgramQuiet[0] != 0) - { - // launch the tool and wait until it finishes - STARTUPINFO si = {0}; - PROCESS_INFORMATION pi; - char currentDir[MAX_PATH]; - char* p; - lstrcpy(currentDir, RemoveRunProgramQuiet); - p = currentDir + lstrlen(currentDir) - 1; - while (*p != '\\' && p > currentDir) - p--; - if (*p == '\\') - *p = 0; - - si.cb = sizeof(STARTUPINFO); - if (!CreateProcess(NULL, RemoveRunProgramQuiet, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, currentDir, &si, &pi)) - { -#ifdef INSIDE_SETUP - if (!SetupInfo.Silent) - { -#endif //INSIDE_SETUP - char errbuff[100]; - DWORD le = GetLastError(); - wsprintf(errbuff, "CreateProcess failed, error=%d", le); - MessageBox(HParent, errbuff, "Error", MB_OK); -#ifdef INSIDE_SETUP - } -#endif //INSIDE_SETUP - } - else - WaitForSingleObject(pi.hProcess, INFINITE); // wait for the tool to finish - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - - if (!LookupForRunningApps(RemoveFiles)) - return FALSE; // cancel - - if (RemoveShellExts[0] != 0) - { - if (!DoRemoveShellExts()) - { - // if we are running as part of installing a new version and the old shell extension could not be renamed (W9x), - // we must ask the user to restart the machine before finishing the installation - if (InsideSetupMode) - { - if (needRestart != NULL) - *needRestart = TRUE; - return FALSE; - } - } - } - - if (UnpinFromTaskbar[0] != 0) - DoUnpinFromTaskbar(UnpinFromTaskbar); - - if (RemoveFiles[0] != 0) - if (!DoRemoveFiles(RemoveFiles)) - return FALSE; - - if (RemoveDirs[0] != 0) - DoRemoveDirs(); - - if (RemoveRegValues[0] != 0) - DoRemoveRegValues(); - - if (RemoveRegKeys[0] != 0) - DoRemoveRegKeys(ParamsGlobal.RemoveConfiguration); - - if (RemoveWERLocalDumps[0] != 0) - DoRemoveWERLocalDumps(); - - return TRUE; -} - -//************************************************************************************ -// -// CleanUp -// - -BOOL CleanUp() -{ - HANDLE hFile; - char tempPath[MAX_PATH]; - char fileName[MAX_PATH]; - const char* nameOnly; - DWORD written; - STARTUPINFO si = {0}; - PROCESS_INFORMATION pi; - char cmdLine[300]; - char* line; - int ret, i; - BOOL ok = TRUE; - - if (GetTempPath(MAX_PATH, tempPath) == 0) - return FALSE; - - if (GetTempFileName(tempPath, "rmb", 1, fileName) == 0) - return FALSE; - - *(strrchr(fileName, '.') + 1) = '\0'; // strip extension TMP - lstrcat(fileName, "bat"); - - nameOnly = strrchr(fileName, '\\') + 1; - if (nameOnly == NULL || *nameOnly == 0) - nameOnly = fileName; - - // create a batch file that deletes us and then itself - hFile = CreateFile(fileName, GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; - - wsprintf(cmdLine, BATCH_FILE_BEGIN, ModuleName, ModuleName); - WriteFile(hFile, cmdLine, lstrlen(cmdLine), &written, NULL); - ok = (written == (DWORD)lstrlen(cmdLine)); - if (ok) - { - for (i = 0; i < 5; i++) // ugly hack, but it should wipe everything down to depth 5 - { - line = RemoveDirs; - while (*line != 0) - { - int len = lstrlen(line); - wsprintf(cmdLine, BATCH_FILE_DELDIR, line); - WriteFile(hFile, cmdLine, lstrlen(cmdLine), &written, NULL); - ok = (written == (DWORD)lstrlen(cmdLine)); - line += len + 1; - } - } - } - if (ok) - { - wsprintf(cmdLine, BATCH_FILE_DELFILE, fileName); - WriteFile(hFile, cmdLine, lstrlen(cmdLine), &written, NULL); - ok = (written == (DWORD)lstrlen(cmdLine)); - } - - if (!ok) - { - DeleteFile(fileName); - CloseHandle(hFile); - return FALSE; - } - CloseHandle(hFile); - - // and run the batch file - si.cb = sizeof(STARTUPINFO); - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - - GetEnvironmentVariable("COMSPEC", cmdLine, MAX_PATH); - lstrcat(cmdLine, " /C "); // run the command and close after it finishes - wsprintf(cmdLine + lstrlen(cmdLine), "\"%s\"", nameOnly); - - SetCurrentDirectory(tempPath); - ret = CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED | NORMAL_PRIORITY_CLASS, NULL, tempPath, &si, &pi); - if (ret == 0) - { - DeleteFile(fileName); - return FALSE; - } - - // Lower the batch file's priority even more. - SetThreadPriority(pi.hThread, THREAD_PRIORITY_IDLE); - - // Raise our priority so that we terminate as quickly as possible. - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); - - // Allow the batch file to run and clean-up our handles. - CloseHandle(pi.hProcess); - ResumeThread(pi.hThread); - // We want to terminate right away now so that we can be deleted - CloseHandle(pi.hThread); - - return TRUE; -} - -BOOL Uninstall(BOOL* needRestart) -{ - BOOL ret = FALSE; - char buff[1024]; - if (!RemoveOpenInfFile()) - { -#ifdef INSIDE_SETUP - if (!QuietMode && !SetupInfo.Silent) -#else //INSIDE_SETUP - if (!QuietMode) -#endif //INSIDE_SETUP - { - wsprintf(buff, LoadStr(IDS_REMOVE_ERROR_LOADINF), RemoveInfFileName); - MessageBox(HParent, buff, LoadStr(IDS_REMOVE_TITLE), MB_OK | MB_ICONEXCLAMATION); - } - return FALSE; - } - - if (DoRemove(needRestart)) - { - if (!QuietMode && !InsideSetupMode) - { - // notify that everything is OK - wsprintf(buff, LoadStr(IDS_REMOVE_SUCCESS), RemoveAppName); - MessageBox(HParent, buff, LoadStr(IDS_REMOVE_TITLE), MB_OK | MB_ICONINFORMATION | MB_TASKMODAL | MB_SETFOREGROUND); - } - // clean up our temporary files - if (!InsideSetupMode) - CleanUp(); - ret = TRUE; - } - - FreeProcesses(); - return ret; -} - -//************************************************************************************ -// -// WinMain -// - -#ifndef INSIDE_SETUP - -/* according to http://vcfaq.mvps.org/sdk/21.htm */ -#define BUFF_SIZE 1024 -BOOL IsUserAdmin() -{ - HANDLE hToken = NULL; - PSID pAdminSid = NULL; - BYTE buffer[BUFF_SIZE]; - PTOKEN_GROUPS pGroups = (PTOKEN_GROUPS)buffer; - DWORD dwSize; // buffer size - DWORD i; - BOOL bSuccess; - SID_IDENTIFIER_AUTHORITY siaNtAuth = SECURITY_NT_AUTHORITY; - - // get token handle - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) - return FALSE; - - bSuccess = GetTokenInformation(hToken, TokenGroups, (LPVOID)pGroups, BUFF_SIZE, &dwSize); - CloseHandle(hToken); - if (!bSuccess) - return FALSE; - - if (!AllocateAndInitializeSid(&siaNtAuth, 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, &pAdminSid)) - return FALSE; - - bSuccess = FALSE; - for (i = 0; (i < pGroups->GroupCount) && !bSuccess; i++) - { - if (EqualSid(pAdminSid, pGroups->Groups[i].Sid)) - bSuccess = TRUE; - } - FreeSid(pAdminSid); - - return bSuccess; -} - -BOOL RunAsAdminAndWait(HWND hWnd, LPTSTR lpFile, LPTSTR lpParameters, DWORD* exitCode) -{ - BOOL ret; - SHELLEXECUTEINFO sei = {0}; - - sei.cbSize = sizeof(SHELLEXECUTEINFO); - sei.hwnd = hWnd; - sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; - sei.lpVerb = "runas"; - sei.lpFile = lpFile; - sei.lpParameters = lpParameters; - sei.nShow = SW_SHOWNORMAL; - - ret = FALSE; - *exitCode = 0; - if (ShellExecuteEx(&sei)) // FALSE can also mean just Cancel - { - ret = TRUE; - if (sei.hProcess != NULL) - { - WaitForSingleObject(sei.hProcess, INFINITE); - if (!GetExitCodeProcess(sei.hProcess, exitCode)) - *exitCode = 0; - CloseHandle(sei.hProcess); - } - } - return ret; -} - -char* SkipExeName(char* cmdline) -{ - // skip leading spaces - while (*cmdline == ' ' || *cmdline == '\t') - cmdline++; - // skip exe name - if (*cmdline == '"') - { - cmdline++; - while (*cmdline != '\0' && *cmdline != '"') - cmdline++; - if (*cmdline == '"') - cmdline++; - } - else - while (*cmdline != '\0' && *cmdline != ' ' && *cmdline != '\t') - cmdline++; - while (*cmdline == ' ' || *cmdline == '\t') - cmdline++; - return cmdline; -} - -void RunRemoveExeAsAdminIfNeeded() -{ - if (!IsUserAdmin()) - { - { - char removeExe[MAX_PATH]; - char params[MAX_PATH]; - DWORD exitCode; - char* p; - BOOL runAsForbidden; - int len; - - char* cmdline = SkipExeName(GetCommandLine()); - lstrcpyn(params, cmdline, MAX_PATH - 3); - len = lstrlen(params); - while (len > 0 && (params[len - 1] == ' ' || params[len - 1] == '\t')) - len--; - lstrcpy(params + len, " /a"); - runAsForbidden = FALSE; - p = cmdline; - while (*p != 0) - { - if ((*p == '/' || *p == '-') && - (*(p + 1) == 'a' || *(p + 1) == 'A') && - (*(p + 2) == ' ' || *(p + 2) == '\t' || *(p + 2) == 0)) - { - runAsForbidden = TRUE; - } - while (*p != 0 && *p != ' ' && *p != '\t') - p++; - while (*p != 0 && (*p == ' ' || *p == '\t')) - p++; - } - - exitCode = 0; - if (!runAsForbidden && GetModuleFileName(NULL, removeExe, MAX_PATH)) - { - MessageBox(NULL, LoadStr(IDS_REMOVE_XPRUNASADMIN), LoadStr(IDS_REMOVE_TITLE), MB_OK | MB_ICONINFORMATION); - if (RunAsAdminAndWait(NULL, removeExe, params, &exitCode)) - { // if another remove.exe is started, terminate this one here - ExitProcess(exitCode); - } - } - } - } -} - -BOOL RefreshDesktop(BOOL sleep) -{ - ITEMIDLIST root = {0}; - SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, &root, 0); - if (sleep) - Sleep(500); // give the system some time - return TRUE; -} - -// **************************************************************************** -// EnableExceptionsOn64 -// - -// We want to be notified about SEH exceptions even on x64 Windows 7 SP1 and later -// http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/ -// http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages -// http://support.microsoft.com/kb/976038 -void EnableExceptionsOn64() -{ - typedef BOOL(WINAPI * FSetProcessUserModeExceptionPolicy)(DWORD dwFlags); - typedef BOOL(WINAPI * FGetProcessUserModeExceptionPolicy)(LPDWORD dwFlags); - typedef BOOL(WINAPI * FIsWow64Process)(HANDLE, PBOOL); -#define PROCESS_CALLBACK_FILTER_ENABLED 0x1 - - HINSTANCE hDLL = LoadLibrary("KERNEL32.DLL"); - if (hDLL != NULL) - { - FIsWow64Process isWow64 = (FIsWow64Process)GetProcAddress(hDLL, "IsWow64Process"); - FSetProcessUserModeExceptionPolicy set = (FSetProcessUserModeExceptionPolicy)GetProcAddress(hDLL, "SetProcessUserModeExceptionPolicy"); - FGetProcessUserModeExceptionPolicy get = (FGetProcessUserModeExceptionPolicy)GetProcAddress(hDLL, "GetProcessUserModeExceptionPolicy"); - if (isWow64 != NULL && set != NULL && get != NULL) - { - BOOL bIsWow64; - if (isWow64(GetCurrentProcess(), &bIsWow64) && bIsWow64) - { - DWORD dwFlags; - if (get(&dwFlags)) - set(dwFlags & ~PROCESS_CALLBACK_FILTER_ENABLED); - } - } - FreeLibrary(hDLL); - } -} - -int CALLBACK -WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - char* p; - HInstance = hInstance; - - EnableExceptionsOn64(); - - RunRemoveExeAsAdminIfNeeded(); - - InitUtils(); - - // we do not want critical errors such as "no disk in drive A:" - SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS); - - OleInitialize(NULL); - - GetModuleFileName(NULL, ModuleName, MAX_PATH); - - lstrcpy(ModulePath, ModuleName); - *(strrchr(ModulePath, '\\')) = '\0'; // Strip setup.exe off path - - InitCommonControls(); - - p = SkipExeName(lpCmdLine); - - if ((*p == '/' || *p == '-') && - (*(p + 1) == 'q' || *(p + 1) == 'Q') && - (*(p + 2) == ' ' || *(p + 2) == '\t' || *(p + 2) == 0)) - { - QuietMode = TRUE; - } - - lstrcpy(RemoveInfFileName, ModulePath); - lstrcat(RemoveInfFileName, INF_REMOVE_FILENAME); - - Uninstall(NULL); - - RefreshDesktop(FALSE); - - OleUninitialize(); - - return 0; -} -#endif //INSIDE_SETUP - -#ifdef INSIDE_SETUP -BOOL DoUninstall(HWND hParent, BOOL* needRestart) -{ - BOOL ret; - if (SetupInfo.TheExistingVersionIsSame) - ReadPreviousVerOfFileToIncrementContent(); - InsideSetupMode = TRUE; - HParent = hParent; - ExpandPath(SetupInfo.SaveRemoveLog); - lstrcpy(RemoveInfFileName, SetupInfo.SaveRemoveLog); - ret = Uninstall(needRestart); - RefreshDesktop(TRUE); - return ret; -} -#endif //INSIDE_SETUP - diff --git a/src/setup/remove/remove.rc b/src/setup/remove/remove.rc deleted file mode 100644 index f8800cd2..00000000 --- a/src/setup/remove/remove.rc +++ /dev/null @@ -1,223 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) - -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// Neutral resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include \0" -END - -3 TEXTINCLUDE -BEGIN - "#ifndef INSIDE_SETUP\r\n" - "#include ""remove.rc2""\r\n" - "#endif\r\n" - "\r\n" - "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY)\r\n" - "LANGUAGE LANG_CZECH, SUBLANG_DEFAULT\r\n" - "#include ""remove_cz.rc2""\r\n" - "LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL\r\n" - "#include ""remove_de.rc2""\r\n" - "LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r\n" - "#include ""remove_en.rc2""\r\n" - "#endif\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // Neutral resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// Czech resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY) -LANGUAGE LANG_CZECH, SUBLANG_DEFAULT - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -#ifndef INSIDE_SETUP -IDD_CONFIRMATION DIALOGEX 85, 45, 336, 102 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Taskscape Ltd Uninstall" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - ICON 3100,IDC_MYICON,10,11,20,20 - DEFPUSHBUTTON "&Ano",IDYES,115,81,50,14,WS_GROUP - PUSHBUTTON "&Ne",IDNO,169,81,50,14 - LTEXT "Opravdu si přejete odstranit %s?",IDC_QUESTION,39,10,290,18 - LTEXT "Obě x64 a x86 verze Open Salamandera sdílí jednu konfiguraci v Registru.",IDC_STATIC,39,36,290,8 - CONTROL "Zároveň odstranit &konfiguraci z Registru",IDC_REMOVECONFIGURATION, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,39,47,164,12 -END -#endif //INSIDE_SETUP - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_CONFIRMATION, DIALOG - BEGIN - RIGHTMARGIN, 329 - BOTTOMMARGIN, 122 - END -END -#endif // APSTUDIO_INVOKED - -#endif // Czech resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// German (Neutral) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) -LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -#ifndef INSIDE_SETUP -IDD_CONFIRMATION DIALOGEX 85, 45, 362, 103 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Taskscape Ltd-Deinstallation" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - ICON 3100,IDC_MYICON,10,11,20,20 - DEFPUSHBUTTON "&Ja",IDYES,125,80,50,14,WS_GROUP - PUSHBUTTON "&Nein",IDNO,179,80,50,14 - LTEXT "Möchten Sie %s wirklich entfernen?",IDC_QUESTION,39,10,305,18 - LTEXT "Beide Versionen von Open Salamander, die x64 und die x86, benutzen dieselbe Konfiguration.",IDC_STATIC,39,36,318,8 - CONTROL "Ebenfalls die &Konfiguration aus der Registry entfernen",IDC_REMOVECONFIGURATION, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,39,47,214,12 -END -#endif //INSIDE_SETUP - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_CONFIRMATION, DIALOG - BEGIN - RIGHTMARGIN, 353 - BOTTOMMARGIN, 96 - END -END -#endif // APSTUDIO_INVOKED - -#endif // German (Neutral) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -#ifndef INSIDE_SETUP -IDD_CONFIRMATION DIALOGEX 85, 45, 337, 100 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Taskscape Ltd Uninstall" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - ICON 3100,IDC_MYICON,10,11,20,20 - DEFPUSHBUTTON "&Yes",IDYES,116,78,50,14,WS_GROUP - PUSHBUTTON "&No",IDNO,170,78,50,14 - LTEXT "Are you sure that you want to remove the %s?",IDC_QUESTION,39,10,293,17 - LTEXT "Both x64 and x86 versions of Open Salamander are sharing the same configuration.",IDC_STATIC,39,35,293,8 - CONTROL "Remove also &configuration from Registry",IDC_REMOVECONFIGURATION, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,39,46,167,12 -END -#endif //INSIDE_SETUP - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_CONFIRMATION, DIALOG - BEGIN - RIGHTMARGIN, 332 - BOTTOMMARGIN, 123 - END -END -#endif // APSTUDIO_INVOKED - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// -#ifndef INSIDE_SETUP -#include "remove.rc2" -#endif - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY) -LANGUAGE LANG_CZECH, SUBLANG_DEFAULT -#include "remove_cz.rc2" -LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL -#include "remove_de.rc2" -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#include "remove_en.rc2" -#endif - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/src/setup/remove/remove.rc2 b/src/setup/remove/remove.rc2 deleted file mode 100644 index 71dcd6ca..00000000 --- a/src/setup/remove/remove.rc2 +++ /dev/null @@ -1,51 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// -// Manifest -// - -CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "manifest.xml" - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -IDI_ICON1 ICON "icon1.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,28,0,0 - PRODUCTVERSION 1,28,0,0 - FILEFLAGSMASK 0x1L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Open Salamander" - VALUE "FileDescription", "Open Salamander Uninstaller" - VALUE "FileVersion", "1.28.0.0" - VALUE "InternalName", "Open Salamander Uninstaller" - VALUE "OriginalFilename", "remove.exe" - VALUE "LegalCopyright", "Copyright © 1997-2023 Taskscape Ltd" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - diff --git a/src/setup/remove/remove_cz.rc2 b/src/setup/remove/remove_cz.rc2 deleted file mode 100644 index 45bb6954..00000000 --- a/src/setup/remove/remove_cz.rc2 +++ /dev/null @@ -1,10 +0,0 @@ -STRINGTABLE -BEGIN - IDS_REMOVE_SUCCESS "Aplikace %s byla spn odinstalovna." - IDS_REMOVE_TITLE "Odinstalace aplikace" - IDS_REMOVE_ERROR_LOADINF "Chyba ten log souboru: %s." - IDS_REMOVE_APPRUNNING "Odinstalan program zjistil, e odinstalovvan aplikace je sputn:\n%s\n\nZavete prosm aplikaci a stisknte Opakovat pro pokraovn." - IDS_REMOVE_DELETEFAILED "Nelze vymazat soubor\n%s\n\n%s" - IDS_REMOVE_XPRUNASADMIN "Pokud jste pro instalaci tto aplikace pouili administrtorsk uet, muste pout stejn et pro jej odinstalovn. et mete zvolit v nsledujcm okn Spustit jako." -END - diff --git a/src/setup/remove/remove_de.rc2 b/src/setup/remove/remove_de.rc2 deleted file mode 100644 index f553da96..00000000 --- a/src/setup/remove/remove_de.rc2 +++ /dev/null @@ -1,10 +0,0 @@ -STRINGTABLE -BEGIN - IDS_REMOVE_SUCCESS "Der %s wurde erfolgreich entfernt." - IDS_REMOVE_TITLE "Anwendung deinstallieren" - IDS_REMOVE_ERROR_LOADINF "Fehler lade Logdatei: %s." - IDS_REMOVE_APPRUNNING "Es wurde festgestellt, dass das zu entfernende Programm noch luft:\n%s\n\nBeenden Sie es bitte und drcken Sie ""Wiederholen"" um fortzufahren." - IDS_REMOVE_DELETEFAILED "Die Datei\n%s\n\n%s kann nicht entfernt werden" - IDS_REMOVE_XPRUNASADMIN "Wenn Sie ein Administratorkonto verwendet haben, um diese Anwendung zu installieren, sollten Sie das Administratorkonto auch verwenden um diese zu entfernen. Sie knnen das Konto im folgenden ""Ausfhren als""-Fenster auswhlen." -END - diff --git a/src/setup/remove/remove_en.rc2 b/src/setup/remove/remove_en.rc2 deleted file mode 100644 index 91b5f634..00000000 --- a/src/setup/remove/remove_en.rc2 +++ /dev/null @@ -1,10 +0,0 @@ -STRINGTABLE -BEGIN - IDS_REMOVE_SUCCESS "The %s was successfully removed." - IDS_REMOVE_TITLE "Uninstall Application" - IDS_REMOVE_ERROR_LOADINF "Error loading log file: %s." - IDS_REMOVE_APPRUNNING "Uninstall has detected that uninstalled application is running:\n%s\n\nPlease close it and click Retry to continue." - IDS_REMOVE_DELETEFAILED "Cannot delete file\n%s\n\n%s" - IDS_REMOVE_XPRUNASADMIN "If you have used some administrator account to install this application, you should use the same administrative account to uninstall it. You can choose account in the following Run As window." -END - diff --git a/src/setup/remove/resource.h b/src/setup/remove/resource.h deleted file mode 100644 index 3100e5b6..00000000 --- a/src/setup/remove/resource.h +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by remove.rc -// -#define IDS_REMOVE_CONFIRMREMOVE 3000 -#define IDS_REMOVE_SUCCESS 3001 -#define IDS_REMOVE_TITLE 3002 -#define IDS_REMOVE_ERROR_LOADINF 3003 -#define IDS_REMOVE_APPRUNNING 3004 -#define IDS_REMOVE_DELETEFAILED 3005 -#define IDS_REMOVE_XPRUNASADMIN 3006 -#define IDI_ICON1 3100 - -#ifndef INSIDE_SETUP - -#define IDD_CONFIRMATION 3200 -#define IDC_QUESTION 3201 -#define IDC_REMOVECONFIGURATION 3202 -#define IDC_MYICON 3204 -#define IDC_STATIC -1 - -#endif // INSIDE_SETUP - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 3300 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 3301 -#define _APS_NEXT_SYMED_VALUE 3300 -#endif -#endif diff --git a/src/setup/remove/utils.c b/src/setup/remove/utils.c deleted file mode 100644 index c1239609..00000000 --- a/src/setup/remove/utils.c +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "precomp.h" - -BYTE LowerCase[256]; - -#ifndef INSIDE_SETUP -int StrICmp(const char* s1, const char* s2) -{ - int res; - while (1) - { - res = (unsigned)LowerCase[*s1] - (unsigned)LowerCase[*s2++]; - if (res != 0) - return (res < 0) ? -1 : 1; // < a > - if (*s1++ == 0) - return 0; // == - } -} -#endif //INSIDE_SETUP - -//************************************************************************************ -// -// MoveFileOnReboot -// - -char* mystrstr(char* a, char* b) -{ - int len_of_a = lstrlen(a) - lstrlen(b); - while (*a && len_of_a >= 0) - { - char *t = a, *u = b; - while (*t && *t == *u) - { - t++; - u++; - } - if (!*u) - return a; - a++; - len_of_a--; - } - return NULL; -} - -void* mini_memcpy(void* out, const void* in, int len) -{ - char* c_out = (char*)out; - char* c_in = (char*)in; - while (len-- > 0) - { - *c_out++ = *c_in++; - } - return out; -} - -BOOL GetFolderPath(int nFolder, LPTSTR pszPath) -{ - HRESULT ret; - *pszPath = 0; - ret = SHGetFolderPath(NULL, nFolder, NULL, 0, pszPath); - return (ret == S_OK); -} - -/* -typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); -LPFN_ISWOW64PROCESS fnIsWow64Process; -BOOL Is64BitWindows() -{ - BOOL bIsWow64 = FALSE; - #ifdef _WIN64 - return TRUE; // 64-bit programs run only on Win64 - #endif - //IsWow64Process is not available on all supported versions of Windows. - //Use GetModuleHandle to get a handle to the DLL that contains the function - //and GetProcAddress to get a pointer to the function if available. - fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle(TEXT("kernel32")),"IsWow64Process"); - if(NULL != fnIsWow64Process) - { - if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) - { - //handle error - } - } - return bIsWow64; -} -*/ - -void InitUtils() -{ - int i; - for (i = 0; i < 256; i++) - LowerCase[i] = (char)CharLower((LPTSTR)(DWORD_PTR)i); -} diff --git a/src/setup/remove/utils.h b/src/setup/remove/utils.h deleted file mode 100644 index 5b9f707c..00000000 --- a/src/setup/remove/utils.h +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -void InitUtils(); - -int StrICmp(const char* s1, const char* s2); -void* mini_memcpy(void* out, const void* in, int len); -char* mystrstr(char* a, char* b); -BOOL GetFolderPath(int nFolder, LPTSTR pszPath); // pszPath must be at least MAX_PATH characters! -//BOOL Is64BitWindows(); diff --git a/src/setup/res/hand.cur b/src/setup/res/hand.cur deleted file mode 100644 index 59475887a21faaf4a016e0475d060f2bcfbc0a87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 326 zcma*hKN0~k7>D6E3|p>>(w0h{lG`|flB4Z042>gf$uQ#GWX&4YCiCQ%FOz>TB2ZN@ z0oDQL=1MNHQ?RGjMK1a=#@H7FX5$yMig#9;rB^Jq&_)OCpD?}ZqO)pw|38=T4};o0 e#Q4>Cs&z|_u_im2bY^DS=eefPR=)J>Vf_KJZF+(L diff --git a/src/setup/res/icon.bmp b/src/setup/res/icon.bmp deleted file mode 100644 index 1917f50745b2f71dfa7e9d3c5421284f095a3e83..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11076 zcmeHLdsviJ8vh-bQdUrIg}IgjZl)mtvTG!P7uwhgY*$2Ux81ee)x43HE|_S9TBed| ziUBHWAc%5NKt(Y{F)jj%8Ui!iX22O>F3g2tZm{n+`k4Fp)I)>)vHQ$)VM8dM!&uXMuQ&8ZUy@L^fcE*)`t$7BNpGr!a6LKS!?I`QZk6^4-6omF92ks8C#sp0aS8lx^~;Bird2_-$4Sf<0% zxlMSkviPMc@@Jf~xeGQK`kNS9>wd1N`=V7W@z7N{_^ zKnZuk^eI+jD#Z;w)r?}P2@+jDShf-@lYFzuj&;L^`mQuTv_ylSh)QtHWmu7tGF4v^2-Er4z4i3;kdG4G-QAGO<&a9H=gsUw=1tVp)S$Am z66NLPC@n3;<;#~*Qc{BA;$jpP6``=O5c&D}IDY&%a&vQ$m6e5~M~@;iGZX3Q=}1dU zLuzU&n6+6Iuqt3xz^Z^%0jmO51*{7E|0}@%H7W81En;c6TBA{SOT{gMUjeJux!Yhe z8R=1#o_wgIS2))`Ttm#5Qr5kPrKNombp6#li#$=7c2ZRAE{ zFVFJG_hyRv)UAvqUd*h@th#h3%}&W@&lc_cxRlR#Au6JKu9kL0rtU_z?^0#u$%2Bc zjJ@VC`-_TpWM@}ZU);;DR}UV9*C%JJ{9I*LetuqFUPhuBqvGt2BPX-7Gpo-eG6$8( zFgUpyb@Ez%Vqr#J-iZ?@jvY@=GAE>>C@(*&;N(d{`JOeZO}&FjJYS`$9g&oAgu>_M z2*xq4H4E{9TZGV{z{CNt?Qu6T)t z&re8?-^RuNVna&G?mILXYrLF!aASPV@ngg#^J0{(*4SVP2b#mzy6|Ju4joEO&H47g zrmu@XiM$uc;o91BSs5oYtLc%yx|DU8dMwOHo0{>9Pwz=AFE9PRw0xiAJp``fxWA$- zx$Jtywd4!mMK)@U&j0oAK!5O65*8aD%ZA$74Yjv-`pIcmE|gM6EL&QF-a3|$z?Ukd z9k)ewKXbDvTPqM63>Ia*Ma3e&`o#VxZ$%EgmO3sAP8HR&oixUlpCtM-e~3Hyvk%1F zb%(wU_bpxg?&81vxU3ixBre{)dr8Cy zyGMs!IhV1=sly~4K*$GNl=W;$%BS0xEL*l@(VKJU&Yd^&zV%u5{>qiB~vOIo@s zE&WoIi?REG00S6MJ47YKMXy}7a>cy4v%%51)@3 zZcq;(4ho@-J*p-oklWvHocZH?4&-yf*m~%^#Tb0Hcs0=on?)po z{euFy>#BbtXo`8)O8(nR9LPr;$hRDZMOrB+AFDWs@aY6GdCDA{S~lXj$!?PamQ&H+ zTKCpV|GZ1&Amu}EQO>*S*!oqRQf7$f=hz9E)85}cG1AR{*@$|^ny(&xjX*de2aB1r z(W1307O|uiW~GQlK%iX%pE8F1;&cppFzYsgFs++EU@b?8=)(<4nrr5%z>z6ixf-Qgd4N7>hfAHh> z3OZ!5t4S!$XsY5y`X4ATv zle`FI?3lnI+>P&t3xpB`=I8(7wCS_L=B-#phictm z&eV+Yx)>u6B0?Y&y}YPA#t{v|2o4ILHE&@OW8Hm&dp2N9M8y{o5bQQ;tcT}#YU4aT z#*8Egk}7oGyRo#uO%LHgikL+D{K0?Z7Fz2*Q_W%zZ5;kO|~{gNGowXis4g z-oN*A8$D*sm?uY(P`>^_p`kNl8Ee((1}oH^#nLFdO`X|3<0!bVpP%pK;Az2AmJouI zq*pn(bl(BsKKU*RA$>(fg!oJfcs^jJ&$8Lv5yeHVduZsj0#*gA3Ro5RpH~3*4<+R_YybcN diff --git a/src/setup/res/setup.ico b/src/setup/res/setup.ico deleted file mode 100644 index 2a7ebda53a2531c4270c5c3b14b8943b11b212c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4710 zcmeH~L5Lhh6hQyzYE3YZ@zi)SLvom5W7q~E(_sxO z3c<$1il}Hnl$=6lql1D6Q|H8hi!LEVW?N=5mmV^j^8M5+J+G^N{a^oA zSM_$)iqvFEcJJOTD$mwLUZgBldF=_2*J+!cF6_TNCUWCR)zw?%)4Ir4JLpGUJ*Gk9 zsdU4An_DcxPh!1kjY_yEyWOsc4?ppgh2m-ADjH0KRuhZA@V1uCrSplFtz<_hl#8PJ z;LPGrp=@`48YQtABxipx&Db=OCK4~?Nh?W`hH17=&CER45aWwdnq?`cKGb%RQJ!2HBGOrRR-KT{6iw+dV5sg6bDF#WfaSR1*;WhE{ZoulrLUHRnu zflN(JNxfc|ojZ5Ro;`bH@7}$#Z{I$dnVFIO`}fQ7e}?hX0;v$w^PE`k&sXoH0aQgGlwoh(FQ!GR~E zA-6n*>z?ZS$LVOWknzb2Oji=vJjCwrF7t_6NoX;4k?i zaYd&-v3tqJX8gc!>Lwebdptty4bLp(%Fwe?$mKoh_yx(xhnVc-{IP>aU-IZ-blJ%} z+ED1~a`KKglsYaa=e41tzofFM4+_cT-}uf>GpNHb*^grOu5BeQzSooQEQ`aJmW%Qq z>_-~XG`9pctqZGcPAaVtTfo9nvYHkR3rlgsv`4?+O4*$Xd)u@Yl3VW;I`&qx-5%Xa z7QdX>Tdh`O$6_bwrCp?RCElR&-yPL_w;{eeEel;{ z5MC&Fl~S4L@;LPx$iu|?n!*S;FVr3YUxS(-{SCj#fD+1sZjjs7HbPP zUh7baOXbmd;?a5H(RqSB{r_{G;7Bq%JFB08?WEW1bk@F^JGjLoTk$L5pdvkE3j2ZO zN{9^eif|I>^*JMS*5(c#SYEC;6#er|*84bg*3>*4ZU!j(=e<5cf&*BQ4Tnkp-b!!~ z!ANb>UgXbvD=T>DV{!hd+QazstoM$J+6MzX{@i~!Twb1=6Y1xEQ0=dKfY5)4_1Njt zSNpl~gF&Ug+A|!~+*-TZSBDL=o}fbiyf=63*y**ks|3i+Y&cJa(H8bR&wHUe_I@6^ zo4%f}%Kq48eVy>wXJ>f;j$!5@yZ65$>+2dZNU*D`&^-@lH`OK*;`2&yP7QV)&KBuE zRiyX9K@Xl=gz#mk5TW#)B==!>8ZRqSV6RnV(_T8LeLO#Z5aD0fTE$*OR{OWFOdPh@ zi*bmry|Ur3)gB%z^q)9vZ>N9hu)TeL!{ION8xDVE4-P!$_V(@Pr(BfqDr`(|b$&{R N^@oIiEB@ni${*Lgo>l+= diff --git a/src/setup/res/welcome.bmp b/src/setup/res/welcome.bmp deleted file mode 100644 index 965e44aa219d8af9db32156be892bd43f618761f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26992 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 diff --git a/src/setup/resource.h b/src/setup/resource.h deleted file mode 100644 index 207aabe8..00000000 --- a/src/setup/resource.h +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Taskscape Ltd -// SPDX-License-Identifier: GPL-2.0-or-later - -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by setup.rc -// -#define EXE_ICON 100 -#define IDB_WELCOME 110 -#define IDB_ICON 111 -#define IDC_HANDICON 120 -#define IDC_WHITE_RECT 900 -#define IDC_BOLDWHITE_TEXT 901 -#define IDC_NORMALWHITE_TEXT 902 -#define IDC_INSTALL_ICON 903 -#define IDC_WWW 904 -#define IDD_WELCOME 1000 -#define IDC_WLC_A 1001 -#define IDC_WLC_B 1002 -#define IDC_WLC_WARNING 1004 -#define IDC_WIZARD_SEPARATOR 1006 -#define IDD_WIZARD 1009 -#define IDD_LICENSE 1010 -#define IDC_SLA_LICENSE 1011 -#define IDC_SLA_BOTTOM 1012 -#define IDD_DESTINATION 1020 -#define IDC_CDL_1 1021 -#define IDC_CDL_PATH 1022 -#define IDC_CDL_BROWSE 1023 -#define IDD_FOLDER 1030 -#define IDC_SPF_DESKTOP 1031 -#define IDC_SPF_LINK 1032 -#define IDC_SPF_PERSONAL 1034 -#define IDC_SPF_COMMON 1035 -//#define IDC_SPF_PINTOTASKBAR 1036 -#define IDC_SPF_FOLDERS 1037 -#define IDD_FINISH 1040 -#define IDC_CYS_TEXT 1041 -#define IDD_EXIT 1050 -#define IDC_ES_1 1051 -#define IDC_ES_2 1052 -#define IDD_DONE 1060 -#define IDC_DONE_TEXT 1061 -#define IDC_DONE_README 1062 -#define IDC_DONE_RUN 1063 -#define IDC_DONE_TEXT2 1064 -#define IDD_UNINSTALL 1069 -#define IDD_PROGRESS 1070 -#define IDC_PGS_FROM 1071 -#define IDC_PGS_TO 1072 -#define IDC_PGS_PGS 1073 -#define IDD_COMMONCONTROL 1080 -#define IDC_CC_VERSION 1081 -#define IDC_CC_VERSION_NEED 1082 -#define IDD_CF_OVERWRITE 1090 -#define IDC_CF_TARGETFILENAME 1091 -#define IDC_CF_TARGETFILEATTR 1092 -#define IDC_CF_SOURCEFILENAME 1093 -#define IDC_CF_SOURCEFILEATTR 1094 -#define IDC_CF_YESALL 1095 -#define IDC_CF_SKIP 1096 -#define IDC_CF_SKIPALL 1097 -#define IDD_CF_RETRY 1100 -#define IDC_CF_RETRYNAME 1101 -#define IDC_CF_RETRYERROR 1102 -#define IDD_README 1120 -#define IDS_WZR_BACK 2000 -#define IDS_WZR_NEXT 2001 -#define IDS_WZR_EXIT 2002 -#define IDS_WZR_YES 2003 -#define IDS_WZR_NO 2004 -#define ERROR_CREATEWIZARD 2005 -#define ERROR_LOADINF 2006 -#define ERROR_LOADLICENSE 2007 -#define IDS_INSTALLING 2008 -#define IDS_CHOOSEDIR 2009 -#define IDS_NODIR 2010 -#define IDS_NOSPACE 2011 -#define IDS_WZR_FINISH 2013 -#define IDS_TARGETDIR 2014 -#define IDS_PERSONAL 2015 -#define IDS_COMMON 2016 -#define IDS_INSERT_DESKTOP 2017 -#define IDS_INSERT_MENU 2018 -#define IDS_INVALIDPATH 2020 -#define IDS_NAMEUSEDFORFILE 2022 -#define IDS_CREATEDIRFAILED 2023 -#define IDS_ERRORCREATELOG 2024 -#define IDS_APPRUNNING 2025 -#define IDS_MAINWINDOWTITLE 2026 -#define IDS_SETUPCOPYRIGHT1 2027 -#define IDS_INSTALL_STOP 2029 -#define IDS_INSTALL_STOP_TITLE 2030 -#define IDS_WIZ_TITLE 2031 -#define IDS_WZR_INSTALL 2032 -#define IDS_INSTFAILED 2033 -#define ERROR_CMDLINE 2036 -#define IDS_CONFLICTWITHNEWER 2038 -#define IDS_INSTNEEDRESTART 2040 -#define IDS_TARGETDIRUPGRADE 2041 -#define IDS_CONFLICTPRIOR 2042 -#define IDS_CONFLICTSAME 2043 -#define IDS_PREVIEWBUILDWARNING 2044 -#define IDS_BETAWARNING 2045 -#define ERROR_CF_OPENFILE 2050 -#define ERROR_CF_FILEINFORMATION 2051 -#define ERROR_CF_CREATEFILE 2052 -#define ERROR_CF_FILESETATTR 2053 -#define ERROR_CF_READFILE 2054 -#define ERROR_CF_WRITEFILE 2055 -#define ERROR_CF_GETATTR 2056 -#define ERROR_DLGCREATE 2057 -#define ERROR_CREATESHORTCUT 2070 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 2080 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 2080 -#define _APS_NEXT_SYMED_VALUE 2080 -#endif -#endif diff --git a/src/setup/setup.rc b/src/setup/setup.rc deleted file mode 100644 index e80fbff4..00000000 --- a/src/setup/setup.rc +++ /dev/null @@ -1,1008 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) - -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winresrc.h" -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// Neutral resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL - -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "manifest.xml" - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,70,0,0 - PRODUCTVERSION 1,70,0,0 - FILEFLAGSMASK 0x1L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Open Salamander" - VALUE "FileDescription", "Open Salamander Setup" - VALUE "FileVersion", "1.70.0.0" - VALUE "InternalName", "Open Salamander Installer" - VALUE "OriginalFilename", "setup.exe" - VALUE "LegalCopyright", "Copyright © 1997-2023 Taskscape Ltd" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -EXE_ICON ICON "res\\setup.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -IDB_WELCOME BITMAP "res\\welcome.bmp" -IDB_ICON BITMAP "res\\icon.bmp" - -///////////////////////////////////////////////////////////////////////////// -// -// Cursor -// - -IDC_HANDICON CURSOR "res\\hand.cur" - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winresrc.h""\0" -END - -3 TEXTINCLUDE -BEGIN - "#define INSIDE_SETUP\r\n" - "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY)\r\n" - "#include ""remove\\resource.h""\r\n" - "LANGUAGE LANG_CZECH, SUBLANG_DEFAULT\r\n" - "#include ""remove\\remove_cz.rc2""\r\n" - "LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL\r\n" - "#include ""remove\\remove_de.rc2""\r\n" - "LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r\n" - "#include ""remove\\remove_en.rc2""\r\n" - "#endif\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // Neutral resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// Czech resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY) -LANGUAGE LANG_CZECH, SUBLANG_DEFAULT - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_WIZARD DIALOGEX 61, 53, 330, 220 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_WIZARD_SEPARATOR,"Static",SS_ETCHEDHORZ | WS_GROUP,0,193,333,1 - LTEXT "Copyright © 1997-2023 Taskscape Ltd",-1,7,197,141,10,NOT WS_GROUP - LTEXT "www.taskscape.com",IDC_WWW,7,208,67,10,NOT WS_GROUP - PUSHBUTTON "",5,165,200,50,14 - PUSHBUTTON "",IDOK,220,200,50,14 - PUSHBUTTON "",IDCANCEL,274,200,50,14 -END - -IDD_CF_OVERWRITE DIALOGEX 61, 53, 349, 89 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Potvrdit nahrazení souboru" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - RTEXT "Nahradit soubor:",-1,5,9,59,8 - LTEXT "fnTarget",IDC_CF_TARGETFILENAME,69,9,275,8 - LTEXT "attrTarget",IDC_CF_TARGETFILEATTR,69,20,275,8 - RTEXT "souborem:",-1,5,39,59,8 - LTEXT "fnSource",IDC_CF_SOURCEFILENAME,69,39,275,8 - LTEXT "attrSource",IDC_CF_SOURCEFILEATTR,69,50,275,8 - DEFPUSHBUTTON "&Ano",IDOK,8,69,60,14 - PUSHBUTTON "&Vše",IDC_CF_YESALL,76,69,60,14 - PUSHBUTTON "&Přeskočit",IDC_CF_SKIP,144,69,60,14 - PUSHBUTTON "Př&eskočit vše",IDC_CF_SKIPALL,212,69,60,14 - PUSHBUTTON "Storno",IDCANCEL,280,69,60,14 -END - -IDD_CF_RETRY DIALOGEX 31, 84, 350, 86 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Chyba při vytváření souboru" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - RTEXT "Soubor:",-1,5,9,46,8 - LTEXT "fnName",IDC_CF_RETRYNAME,59,9,279,8 - RTEXT "Chyba:",-1,20,29,31,8 - LTEXT "fnError",IDC_CF_RETRYERROR,59,29,279,21 - PUSHBUTTON "&Opakovat",IDOK,43,64,60,14 - PUSHBUTTON "&Přeskočit",IDC_CF_SKIP,111,64,60,14 - PUSHBUTTON "Př&eskočit vše",IDC_CF_SKIPALL,179,64,60,14 - PUSHBUTTON "Storno",IDCANCEL,247,64,60,14 -END - -IDD_COMMONCONTROL DIALOGEX 84, 53, 280, 107 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Instalační program" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Vaše verze COMCTL32.DLL je:",-1,6,40,104,8 - LTEXT "Text",IDC_CC_VERSION,111,40,60,8 - DEFPUSHBUTTON "OK",IDOK,114,87,50,14,WS_GROUP - LTEXT "Používáte starou verzi systémové knihovny COMCTL32.DLL. Instalovaný program",-1,6,7,270,8 - LTEXT "vyžaduje COMCTL32.DLL ve verzi %d.%d nebo novější.",IDC_CC_VERSION_NEED,6,15,270,8 - LTEXT "Nainstalujte prosím volně dostupnou aktualizaci knihovny COMCTL32.DLL.",-1,6,23,270,8 - LTEXT "Poslední verze knihovny COMCTL32.DLL je dostupná na:",-1,6,57,205,8 - EDITTEXT -1,4,67,268,10,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP -END - -IDD_DESTINATION DIALOGEX 35, 58, 330, 159 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Zvolte cílový adresář" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Zvolte cílový adresář",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Zvolte adresář, do kterého si přejete nainstalovat program.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - LTEXT "Instalační program bude instalovat program %s do následujícího adresáře.",IDC_CDL_1,22,51,303,8 - LTEXT "&Cílový adresář",-1,22,68,78,8 - EDITTEXT IDC_CDL_PATH,22,78,229,13,ES_AUTOHSCROLL - PUSHBUTTON "&Procházet",IDC_CDL_BROWSE,257,77,50,15 - LTEXT "Pro instalaci do tohoto adresáře klikněte na tlačítko Další.",-1,22,110,273,8 - LTEXT "Pro instalaci do jiného adresáře napište cestu nebo klikněte na tlačítko Procházet.",-1,22,120,286,8 - LTEXT "Poznámka: pro upgrade starší verze (nebo opravu současné verze) zvolte její adresář.",-1,22,140,299,8 -END - -IDD_DONE DIALOGEX 0, 0, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Dokončeno" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Instalační program dokončil instalaci programu %s na Váš počítač. Program lze spustit kliknutím na jeho zástupce.",IDC_DONE_TEXT,13,13,191,37 - LTEXT "Klikněte na tlačítko Dokončit pro ukončení instalačního programu.",-1,13,131,236,11 - CONTROL "&Zobrazit Čti mě",IDC_DONE_README,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,151,119,10 - CONTROL "&Spustit %s",IDC_DONE_RUN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,166,219,10 -END - -IDD_FINISH DIALOGEX 0, 0, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Potvrďte svůj výběr" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Připraveno k instalaci",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Instalace programu %s na Váš počítač je připravena.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - LTEXT "&Aktuální nastavení:",-1,22,40,80,8 - EDITTEXT IDC_CYS_TEXT,22,50,284,106,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY - LTEXT "Klikněte na tlačítko Instalovat pro spuštění instalace nebo na tlačítko Zpět, pokud si přejete změnit nastavení.",-1,22,160,278,16 -END - -IDD_FOLDER DIALOGEX 54, 36, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Zvolte složky" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Zástupce programu",IDC_BOLDWHITE_TEXT,12,8,126,8 - LTEXT "Instalační program vytvoří následující zástupce.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - LTEXT "Zvolte, kam si přejete nainstalovat zástupce programu:",-1,20,50,209,8 - CONTROL "&Plocha",IDC_SPF_DESKTOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,61,54,12 - CONTROL "&Nabídka Start",IDC_SPF_LINK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,73,73,12 - //CONTROL "&Pin to Taskbar",IDC_SPF_PINTOTASKBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,85,153,12 // disabled option kept for reference - LTEXT "Instalovat zástupce pro:",IDC_SPF_FOLDERS,19,111,197,8 - CONTROL "&Aktuálního uživatele",IDC_SPF_PERSONAL,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,29,122,96,12 - CONTROL "&Všechny uživatele",IDC_SPF_COMMON,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,29,134,108,12 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 -END - -IDD_LICENSE DIALOGEX 10, 20, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Souhlas s licenční smlouvou" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Licenční smlouva",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Než budete pokračovat, přečtěte si prosím následující důležité informace.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - LTEXT "Přečtěte si prosím následující licenční smlouvu. Použijte posuvník nebo stiskněte klávesu Page Down pro zobrazení zbytku licenční smlouvy.",-1,22,43,288,18 - EDITTEXT IDC_SLA_LICENSE,22,64,286,102,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL - LTEXT "Souhlasíte s licenční smlouvou? Pokud zvolíte Ne, instalační program se ukončí. Pro instalaci programu %s, musíte stisknout tlačítko Ano.",IDC_SLA_BOTTOM,22,169,293,16 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 -END - -IDD_PROGRESS DIALOGEX 0, 0, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Kopírování" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Informace o instalaci",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Vyčkejte prosím, dokud instalační program kopíruje soubory na Váš počítač.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - RTEXT "Z:",-1,23,46,18,8 - CONTROL "",IDC_PGS_FROM,"Static",SS_SIMPLE | SS_NOPREFIX,50,46,256,8 - RTEXT "Do:",-1,23,60,18,8 - CONTROL "",IDC_PGS_TO,"Static",SS_SIMPLE | SS_NOPREFIX,50,60,256,8 - LTEXT "Celkem:",-1,17,83,30,8 - CONTROL "Progress1",IDC_PGS_PGS,"msctls_progress32",WS_BORDER,50,82,256,11 -END - -IDD_README DIALOGEX 10, 20, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Čti mě" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Čti mě",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Přečtěte si prosím následujíci důležité informace, než budete pokračovat.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - EDITTEXT IDC_SLA_LICENSE,6,41,319,143,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 -END - -IDD_UNINSTALL DIALOGEX 0, 0, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Odinstalace" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Informace o odinstalaci",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Vyčkejte prosím, instalační program odstraňuje předchozí verzi programu.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - LTEXT "Soubor:",-1,18,46,29,8 - CONTROL "",IDC_PGS_FROM,"Static",SS_SIMPLE | SS_NOPREFIX,50,46,256,8 -END - -IDD_WELCOME DIALOGEX 10, 20, 331, 194 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Vítejte" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Vítejte v instalaci programu %s",IDC_WLC_A,13,13,204,25 - LTEXT "Tento průvodce Vás provede instalací programu\n%s",IDC_WLC_B,13,44,181,21 - LTEXT "Klikněte na tlačítko Další pro pokračování.",IDC_WLC_WARNING,13,131,305,52 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_WELCOME, DIALOG - BEGIN - RIGHTMARGIN, 330 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_WZR_BACK "< &Zpět" - IDS_WZR_NEXT "&Další >" - IDS_WZR_EXIT "Storno" - IDS_WZR_YES "&Ano" - IDS_WZR_NO "&Ne" - ERROR_CREATEWIZARD "Chyba při vytváření dialogu průvodce" - ERROR_LOADINF "Chyba při přístupu k souboru: %s." - ERROR_LOADLICENSE "Chyba při přístupu k licenčnímu souboru." - IDS_INSTALLING "%s" - IDS_CHOOSEDIR "Zvolte adresář" - IDS_NODIR "Adresář:\n\n'%s'\n\nneexistuje. Chcete ho vytvořit?" - IDS_NOSPACE "Na disku %s není dostatek místa\n\npotřebné místo: %ld bytů\ndostupné místo: %ld bytů\n\nUvoněte prosím místo na disku.\nStiskněte Storno, pokud chcete ignorovat toto varování." - IDS_WZR_FINISH "&Dokončit" - IDS_TARGETDIR "Cílový adresář" - IDS_PERSONAL "Zástupce pouze pro aktuálního uživatele" -END - -STRINGTABLE -BEGIN - IDS_WZR_INSTALL "&Instalovat" - IDS_INSTFAILED "Instalace není kompletní. Program %s není nainstalován.\n\nInstalační program můžete spustit později a instalaci dokončit." - ERROR_CMDLINE "Použití:\nSETUP [/?] [/s] [/d dest_dir] [/id ] [/is ] [/au ]\n\n[x] znamená, že je parametr x nepovinný.\n znamená, že jsou parametry y nebo n povinné.\n\n/? -- Zobrazí tuto zprávu o použití.\n/s -- Tichá instalace.\n/d -- Cílový adresář.\n/id -- Nainstalovat zástupce na plochu.\n/is -- Nainstalovat zástupce do nabídky Start.\n/au -- Společné složky všech uživatelů." - IDS_CONFLICTWITHNEWER "Adresář '%s' již obsahuje novější verzi instalovaného programu.\n\nPro instalaci do tohoto adresáře napřed odinstalujte existující Open Salamander.\n\nPřípadně můžete zvolit jiný adresář." - IDS_INSTNEEDRESTART "Instalace nebyla dokončena. Pro dokončení instalace je potřeba provést restart Windows, po kterém se odinstalují shell extensions.\n\nRestartujte prosím Windows a spusťte tento instalační program znovu pro dokončení instalace." - IDS_TARGETDIRUPGRADE "Cílový adresář (upgrade)" - IDS_CONFLICTPRIOR "Adresář '%s' již obsahuje starší verzi instalovaného programu.\n\nStiskněte OK pro jeho upgrade.\nStiskněte Storno pro instalaci do jiného adresáře." - IDS_CONFLICTSAME "Adresář '%s' již obsahuje stejnou verzi instalovaného programu.\n\nStiskněte OK pro jeho opravu.\nStiskněte Storno pro instalaci do jiného adresáře." - IDS_PREVIEWBUILDWARNING "Toto je PREVIEW BUILD programu Open Salamander, uvolněný v Early Access Programu. Tato verze by neměla být používána v produkčním prostředí. Používejte ji pouze pro testování. Těšíme se na Vaše připomínky a náměty, které vkládejte do Early Access Program sekce .\nPoznámka: tato verze je časově omezená." - IDS_BETAWARNING "Toto je BETA verze programu Open Salamander. Tato verze by neměla být používána v produkčním prostředí. Používejte ji pouze pro testování. Těšíme se na Vaše připomínky a náměty, které vkládejte .\nPoznámka: tato verze je časově omezená." -END - -STRINGTABLE -BEGIN - IDS_COMMON "Zástupce pro všechny uživatele" - IDS_INSERT_DESKTOP "Vložit zástupce programu na plochu" - IDS_INSERT_MENU "Vložit zástupce programu do nabídky Start" - IDS_INVALIDPATH "Cílový adresář '%s' je neplatný." - IDS_NAMEUSEDFORFILE "Název ""%s"" byl již použit po jiný soubor." - IDS_CREATEDIRFAILED "Nelze vytvořít adresář:\n%s" - IDS_ERRORCREATELOG "Chyba při vytváření log souboru %s." - IDS_APPRUNNING "Instalační program detekoval, že instalovaný program je spuštěný.\nZavřete prosím program a stiskněte OK pro pokračování.\nTitulek programu je %s." - IDS_MAINWINDOWTITLE "Instalační program" - IDS_SETUPCOPYRIGHT1 "Copyright © 1997-2023 Taskscape Ltd" - IDS_INSTALL_STOP "Instalace není kompletní. Pokud ji nyní ukončíte, program nebude nainstalován.\n\nInstalační program můžete spustit později a instalaci dokončit.\n\nUkončit instalaci?" - IDS_INSTALL_STOP_TITLE "Ukončit instalační program" - IDS_WIZ_TITLE "Instalační program - %s" -END - -STRINGTABLE -BEGIN - ERROR_CF_OPENFILE "Chyba při otevírání souboru %s\n" - ERROR_CF_FILEINFORMATION "Chyba při získávání informací o souboru %s\n" - ERROR_CF_CREATEFILE "Chyba při vytváření souboru %s\n" - ERROR_CF_FILESETATTR "Chyba při nastavování atributů souboru %s\n" - ERROR_CF_READFILE "Chyba při čtení ze souboru %s\n" - ERROR_CF_WRITEFILE "Chyba při zápisu do souboru %s\n" - ERROR_CF_GETATTR "Chyba při získávání atributů: " - ERROR_DLGCREATE "Chyba při otevírání dialogu: " -END - -STRINGTABLE -BEGIN - ERROR_CREATESHORTCUT "Chyba (%08X) při vytváření zástupce %s\n" -END - -#endif // Czech resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// German (Neutral) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) -LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_WIZARD DIALOGEX 61, 53, 360, 220 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_WIZARD_SEPARATOR,"Static",SS_ETCHEDHORZ | WS_GROUP,0,193,363,1 - LTEXT "Copyright © 1997-2023 Taskscape Ltd",-1,7,197,141,10,NOT WS_GROUP - LTEXT "www.taskscape.com",IDC_WWW,7,208,62,10,NOT WS_GROUP - PUSHBUTTON "",5,195,200,50,14 - PUSHBUTTON "",IDOK,250,200,50,14 - PUSHBUTTON "",IDCANCEL,304,200,50,14 -END - -IDD_WELCOME DIALOGEX 23, 32, 360, 194 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Willkommen" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Willkommen zum %s Setup-Programm.",IDC_WLC_A,13,13,231,25 - LTEXT "Dieser Assistent wird Sie durch die Installation von\n%s führen.",IDC_WLC_B,13,44,195,21 - LTEXT "Klicken Sie auf ""Weiter"", um fortzufahren.",IDC_WLC_WARNING,13,131,333,52 -END - -IDD_LICENSE DIALOGEX 10, 20, 360, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Software-Lizenzvereinbarung" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,361,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Lizenzvereinbarung",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren.",IDC_NORMALWHITE_TEXT,22,18,294,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,320,0,36,36 - LTEXT "Lesen Sie bitte die folgende Lizenzvereinbarung. Benutzen Sie die Bildlaufleiste oder drücken Sie die ""Bild-runter""-Taste um den Rest der Vereinbarung anzusehen.",-1,22,43,316,18 - EDITTEXT IDC_SLA_LICENSE,22,64,320,94,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL - LTEXT "Akzeptieren Sie alle Bedingungen der oberen Lizenzvereinbarung? Wenn Sie ""Nein"" wählen, wird das Setup beendet. Um %s zu installieren, müssen Sie der Vereinbarung zustimmen.",IDC_SLA_BOTTOM,22,161,300,24 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,363,1 -END - -IDD_README DIALOGEX 10, 20, 360, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Liesmich" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,361,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Liesmich",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren.",IDC_NORMALWHITE_TEXT,22,18,281,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,320,0,36,36 - EDITTEXT IDC_SLA_LICENSE,6,41,349,143,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,363,1 -END - -IDD_DESTINATION DIALOGEX 35, 58, 360, 175 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Zielordner wählen" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,361,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Zielverzeichnis wählen",IDC_BOLDWHITE_TEXT,12,8,102,8 - LTEXT "Wählen Sie das Verzeichnis, in dem das Setup die Dateien installieren soll.",IDC_NORMALWHITE_TEXT,22,18,296,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,320,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,363,1 - LTEXT "Das Setup wird %s in das folgende Verzeichnis installieren.",IDC_CDL_1,22,51,325,8 - LTEXT "&Zielverzeichnis",-1,22,68,78,8 - EDITTEXT IDC_CDL_PATH,22,78,259,13,ES_AUTOHSCROLL - PUSHBUTTON "D&urchsuchen",IDC_CDL_BROWSE,287,77,57,15 - LTEXT "Klicken Sie auf ""Weiter"", um in dieses Verzeichnis zu installieren.",-1,22,110,310,8 - LTEXT "Um in ein anderes Verzeichnis zu installieren, geben Sie das neue Zielverzeichnis an oder klicken Sie auf ""Durchsuchen"".",-1,22,120,263,16 - LTEXT "Hinweis: Wenn Sie eine ältere Version aktualisieren (oder reparieren) möchten, geben Sie das entsprechende Verzeichnis an.",-1,22,148,263,16 -END - -IDD_FOLDER DIALOGEX 54, 36, 360, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Startmenü-Ordner auswählen" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,361,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Programm-Verknüpfungen",IDC_BOLDWHITE_TEXT,12,8,126,8 - LTEXT "Das Setup wird die Programm-Verknüpfungen hinzufügen.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,363,1 - LTEXT "Wählen Sie, wo Sie die Programm-Verknüpfung installieren möchten:",-1,20,50,244,8 - CONTROL "&Desktop",IDC_SPF_DESKTOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,61,50,12 - CONTROL "&Startmenü",IDC_SPF_LINK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,73,63,12 - //CONTROL "An &Taskleiste anheften", IDC_SPF_PINTOTASKBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,85,87,12 // disabled option kept for reference - LTEXT "Installiere Verknüpfungen für:",IDC_SPF_FOLDERS,19,111,197,8 - CONTROL "&Aktuellen Benutzer",IDC_SPF_PERSONAL,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,29,122,89,12 - CONTROL "A&lle Benutzer",IDC_SPF_COMMON,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,29,134,70,12 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,320,0,36,36 -END - -IDD_FINISH DIALOGEX 16, 26, 360, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Bestätigen Sie Ihre Auswahl" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,361,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Installation durchführen",IDC_BOLDWHITE_TEXT,12,8,102,8 - LTEXT "Das Setup ist jetzt bereit, %s auf Ihrem Computer zu installieren.",IDC_NORMALWHITE_TEXT,22,18,293,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,320,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,363,1 - LTEXT "&Aktuelle Einstellungen:",-1,22,40,94,8 - EDITTEXT IDC_CYS_TEXT,22,50,314,106,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY - LTEXT "Klicken Sie auf ""Installieren"", um mit der Installation fortzufahren oder klicken Sie auf ""Zurück"", wenn Sie die Einstellungen überprüfen oder ändern möchten.",-1,22,160,312,16 -END - -IDD_UNINSTALL DIALOGEX 39, 38, 360, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Deinstallieren" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,361,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Setup Status",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Bitte warten Sie während das Setup die frühere Version der Anwendung entfernt.",IDC_NORMALWHITE_TEXT,22,18,293,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,320,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,363,1 - LTEXT "Datei:",-1,22,46,25,8 - CONTROL "",IDC_PGS_FROM,"Static",SS_SIMPLE | SS_NOPREFIX,50,46,304,8 -END - -IDD_PROGRESS DIALOGEX 16, 29, 360, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Fortschritt" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,361,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Setup Status",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Warten Sie bitte während das Setup Dateien auf Ihren Computer kopiert.",IDC_NORMALWHITE_TEXT,22,18,292,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,320,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,363,1 - LTEXT "Von:",-1,22,46,22,8 - CONTROL "",IDC_PGS_FROM,"Static",SS_SIMPLE | SS_NOPREFIX,63,46,287,8 - LTEXT "Nach:",-1,22,60,22,8 - CONTROL "",IDC_PGS_TO,"Static",SS_SIMPLE | SS_NOPREFIX,63,60,287,8 - LTEXT "Insgesamt:",-1,22,83,40,8 - CONTROL "Progress1",IDC_PGS_PGS,"msctls_progress32",WS_BORDER,63,82,285,11 -END - -IDD_DONE DIALOGEX 17, 29, 360, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Beendet" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Das Setup hat die Installation von %s auf Ihren Computer abgeschlossen. Die Anwendung kann über die installierten Programm-Verknüpfungen gestartet werden.",IDC_DONE_TEXT,13,13,228,32 - LTEXT "Klicken Sie auf ""Fertigstellen"", um das Setup zu beenden.",-1,13,131,228,11 - CONTROL "&Liesmich anzeigen",IDC_DONE_README,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,151,184,10 - CONTROL "&%s starten",IDC_DONE_RUN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,166,232,10 -END - -IDD_COMMONCONTROL DIALOGEX 84, 53, 322, 107 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Setup" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Ihre Version von COMCTL32.DLL ist:",-1,6,40,123,8 - LTEXT "Text",IDC_CC_VERSION,130,40,111,8 - DEFPUSHBUTTON "OK",IDOK,135,87,50,14,WS_GROUP - LTEXT "Sie benutzen eine alte Version der Systembibliothek COMCTL32.DLL. Installierte Anwendung",-1,6,7,311,8 - LTEXT "Benötigte COMCTL32.DLL Version %d.%d oder neuer.",IDC_CC_VERSION_NEED,6,15,311,8 - LTEXT "Bitte zögern Sie nicht und installieren Sie die kostenlose aktuelle COMCTL32.DLL Bibliothek.",-1,6,23,311,8 - LTEXT "Downloadseiten der neusten Version von COMCTL32.DLL:",-1,6,57,213,8 - EDITTEXT -1,4,67,305,10,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP -END - -IDD_CF_OVERWRITE DIALOGEX 63, 56, 366, 89 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Überschreiben der Datei bestätigen" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - RTEXT "Datei überschreiben:",-1,5,9,73,8 - LTEXT "fnZiel",IDC_CF_TARGETFILENAME,83,9,278,8 - LTEXT "attrZiel",IDC_CF_TARGETFILEATTR,83,20,278,8 - RTEXT "Mit Datei:",-1,5,39,73,8 - LTEXT "fnQuelle",IDC_CF_SOURCEFILENAME,83,39,278,8 - LTEXT "attrQuelle",IDC_CF_SOURCEFILEATTR,83,50,278,8 - DEFPUSHBUTTON "&Ja",IDOK,19,69,50,14 - PUSHBUTTON "&Alles",IDC_CF_YESALL,77,69,50,14 - PUSHBUTTON "&Überspringen",IDC_CF_SKIP,135,69,72,14 - PUSHBUTTON "Alles üb&erspringen",IDC_CF_SKIPALL,215,69,72,14 - PUSHBUTTON "Abbrechen",IDCANCEL,295,69,50,14 -END - -IDD_CF_RETRY DIALOGEX 31, 84, 350, 86 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Fehler beim Dateierstellen" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - RTEXT "Erstelle Datei:",-1,4,9,50,8 - LTEXT "fnName",IDC_CF_RETRYNAME,62,9,284,8 - RTEXT "Fehler:",-1,4,29,50,8 - LTEXT "fnFehler",IDC_CF_RETRYERROR,62,29,284,21 - PUSHBUTTON "&Wiederholen",IDOK,31,64,72,14 - PUSHBUTTON "&Überspringen",IDC_CF_SKIP,110,64,72,14 - PUSHBUTTON "&Alles überspringen",IDC_CF_SKIPALL,189,64,72,14 - PUSHBUTTON "Abbrechen",IDCANCEL,268,64,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_WZR_BACK "< &Zurück" - IDS_WZR_NEXT "&Weiter >" - IDS_WZR_EXIT "Abbrechen" - IDS_WZR_YES "&Ja" - IDS_WZR_NO "&Nein" - ERROR_CREATEWIZARD "Erstellen des Setup-Assistenten fehlgeschlagen" - ERROR_LOADINF "Fehler beim Zugriff auf Datei: %s." - ERROR_LOADLICENSE "Fehler beim Zugriff auf Lizenzdatei." - IDS_INSTALLING "%s" - IDS_CHOOSEDIR "Wählen Sie das Verzeichnis" - IDS_NODIR "Das Verzeichnis:\n\n'%s'\n\nexistiert nicht. Soll das Verzeichnis erstellt werden?" - IDS_NOSPACE "Nicht genug Speicherplatz auf Laufwerk %s \n\nBenötigter Platz: %ld Bytes\nVorhandener Platz: %ld Bytes\n\nGeben Sie bitte mehr Speicherplatz frei.\nDrücken Sie ""Abbrechen"" um diese Warnung zu ignorieren." - IDS_WZR_FINISH "&Fertigstellen" - IDS_TARGETDIR "Zielverzeichnis" - IDS_PERSONAL "Verknüpfungen nur für aktuellen Benutzer" -END - -STRINGTABLE -BEGIN - IDS_WZR_INSTALL "&Installieren" - IDS_INSTFAILED "Das Setup ist noch nicht abgeschlossen. Die Anwendung %s wurde nicht installiert.\n\nSie können das Setup zu einem späteren Zeitpunkt nochmals ausführen, um die Installation zu vervollständigen." - ERROR_CMDLINE "Verwendung:\nSETUP [/?] [/s] [/d Ziel_Verz] [/id ] [/is ] [/au ]\n\n[x] bedeutet, dass der Parameter x optional ist.\n bedeutet, dass der Parameter y oder n benötigt wird.\n\n/? -- Generiert diesen Nutzungshinweis.\n/s -- Automatische unbeaufsichtigte Installation.\n/d -- Zielverzeichnis.\n/id -- Installiert Desktop-Verknüpfung.\n/is -- Installiert Startmenü-Verknüpfung.\n/au -- Für alle Benutzer gemeinsame Ordner." - IDS_CONFLICTWITHNEWER "Das Verzeichnis '%s' enthält bereits eine neuere Version der installierten Anwendung.\n\nUm in dieses Verzeichnis zu installieren, müssen Sie die jetzige Version entfernen. Anschließend können Sie diese Version von Open Salamander installieren.\n\nAlternativ können Sie auch ein anderes Verzeichnis wählen." - IDS_INSTNEEDRESTART "Das Setup ist noch nicht abgeschlossen. Ein Windows-Neustart ist nötig um die verwendeten Shell-Erweiterungen zu deinstallieren.\n\nBitte starten Sie Windows neu und führen Sie das Setup nochmals aus um die Installation zu vervollständigen." - IDS_TARGETDIRUPGRADE "Zielverzeichnis (Aktualisierung)" - IDS_CONFLICTPRIOR "Das Verzeichnis '%s' enthält bereits eine frühere Version der installierten Anwendung.\n\nDrücken Sie ""OK"", um diese zu aktualisieren.\nDrücken Sie auf ""Abbrechen"", um sie in ein anderes Verzeichnis zu installieren." - IDS_CONFLICTSAME "Das Verzeichnis '%s' enthält bereits die selbe Version der installierten Anwendung.\n\nDrücken Sie ""OK"", um diese zu reparieren.\nDrücken Sie auf ""Abbrechen"", um sie in ein anderes Verzeichnis zu installieren." - IDS_PREVIEWBUILDWARNING "Dies ist eine Vorabversion von Open Salamander, veröffentlicht im Early Access Programm. Sie sollte NICHT in Produktionsumgebungen verwendet werden. Benutzen Sie diese nur für Testzwecke. Wir freuen uns auf Ihre Meinung in der ""Early Access Program Section"" im .\nHinweis: diese Version ist zeitlich begrenzt." - IDS_BETAWARNING "Dies ist eine BETA Version von Open Salamander. Sie sollte NICHT in Produktionsumgebungen verwendet werden. Benutzen Sie diese nur für Testzwecke. Wir freuen uns auf Ihre Meinung im .\nHinweis: diese Version ist zeitlich begrenzt." -END - -STRINGTABLE -BEGIN - IDS_COMMON "Verknüpfungen für alle Benutzer" - IDS_INSERT_DESKTOP "Programm-Verknüpfung auf dem Desktop anlegen" - IDS_INSERT_MENU "Programm-Verknüpfung für das Startmenü anlegen" - IDS_INVALIDPATH "Das Zielbverzeichnis '%s' ist ungültig." - IDS_NAMEUSEDFORFILE "Der Name ""%s"" wurde bereits für eine Datei verwendet." - IDS_CREATEDIRFAILED "Kann das neue Verzeichnis nicht erstellen:\n%s" - IDS_ERRORCREATELOG "Erstellen der Logdatei %s fehlgeschlagen." - IDS_APPRUNNING "Das Setup hat festgestellt, dass die Anwendung bereits läuft.\nSchließen Sie diese bitte und klicken Sie ""OK"" um fortzufahren.\nName der Anwendung lautet %s." - IDS_MAINWINDOWTITLE "Setup" - IDS_SETUPCOPYRIGHT1 "Copyright © 1997-2023 Taskscape Ltd" - IDS_INSTALL_STOP "Das Setup ist noch nicht abgeschlossen. Wenn Sie jetzt beenden, wird das Programm nicht installiert.\n\nSie können das Setup zu einem späteren Zeitpunkt nochmals ausführen, um die Installation zu vervollständigen.\n\nSetup verlassen?" - IDS_INSTALL_STOP_TITLE "Setup verlassen" - IDS_WIZ_TITLE "Setup - %s" -END - -STRINGTABLE -BEGIN - ERROR_CF_OPENFILE "Fehler beim Öffnen der Datei %s\n" - ERROR_CF_FILEINFORMATION "Fehler beim Abrufen der Dateiinformationen %s\n" - ERROR_CF_CREATEFILE "Fehler beim Erstellen der Datei %s\n" - ERROR_CF_FILESETATTR "Fehler beim Setzen von Dateiattributen %s\n" - ERROR_CF_READFILE "Fehler beim Lesen der Datei %s\n" - ERROR_CF_WRITEFILE "Fehler beim Schreiben der Datei %s\n" - ERROR_CF_GETATTR "Fehler beim Abrufen der Dateiattribute: " - ERROR_DLGCREATE "Fehler beim Erstellen des Dialogfensters: " -END - -STRINGTABLE -BEGIN - ERROR_CREATESHORTCUT "Fehler (%08X) beim Erstellen der Verknüpfung %s\n" -END - -#endif // German (Neutral) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_WIZARD DIALOGEX 61, 53, 330, 220 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_WIZARD_SEPARATOR,"Static",SS_ETCHEDHORZ | WS_GROUP,0,193,333,1 - LTEXT "Copyright © 1997-2023 Taskscape Ltd",-1,7,197,141,10,NOT WS_GROUP - LTEXT "www.taskscape.com",IDC_WWW,7,208,63,10,NOT WS_GROUP - PUSHBUTTON "",5,165,200,50,14 - PUSHBUTTON "",IDOK,220,200,50,14 - PUSHBUTTON "",IDCANCEL,274,200,50,14 -END - -IDD_WELCOME DIALOGEX 10, 20, 330, 194 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Welcome" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Welcome to the %s setup program",IDC_WLC_A,13,13,203,25 - LTEXT "This wizard will guide you through installation of\n%s",IDC_WLC_B,13,44,173,21 - LTEXT "Click Next to continue.",IDC_WLC_WARNING,13,131,304,52 -END - -IDD_LICENSE DIALOGEX 10, 20, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Software License Agreement" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "License agreement",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Please read the following important information before continuing.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - LTEXT "Please read the following License Agreement. Use the scroll bar or press the Page Down key to view the rest of the agreement.",-1,22,43,288,18 - EDITTEXT IDC_SLA_LICENSE,22,64,286,102,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL - LTEXT "Do you accept all the terms of the preceding License Agreement? If you choose No, Setup will close. To install %s, you must accept this agreement.",IDC_SLA_BOTTOM,22,169,293,16 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 -END - -IDD_README DIALOGEX 10, 20, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Read Me" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Read Me",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Please read the following important information before continuing.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - EDITTEXT IDC_SLA_LICENSE,6,41,319,143,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 -END - -IDD_DESTINATION DIALOGEX 35, 58, 330, 159 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Choose Destination Location" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Select Destination Directory",IDC_BOLDWHITE_TEXT,12,8,119,8 - LTEXT "Select the directory you would like Setup to install files.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - LTEXT "Setup will install %s into the following directory.",IDC_CDL_1,22,51,248,8 - LTEXT "&Destination Directory",-1,22,68,97,8 - EDITTEXT IDC_CDL_PATH,22,78,229,13,ES_AUTOHSCROLL - PUSHBUTTON "B&rowse",IDC_CDL_BROWSE,257,77,50,15 - LTEXT "To install to this directory, click Next.",-1,22,110,146,8 - LTEXT "To install to different directory, type the new destination directory or click Browse.",-1,22,120,290,8 - LTEXT "Note: to upgrade a prior version (or repair current version) specify its directory.",-1,22,140,284,8 -END - -IDD_FOLDER DIALOGEX 54, 36, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Select Application Folder" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Program shortcuts",IDC_BOLDWHITE_TEXT,12,8,126,8 - LTEXT "Setup will add the program shortcuts.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - LTEXT "Select where you want to install program shortcut:",-1,20,50,189,8 - CONTROL "&Desktop",IDC_SPF_DESKTOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,61,55,12 - CONTROL "&Start Menu",IDC_SPF_LINK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,73,68,12 - //CONTROL "&Pin to Taskbar", IDC_SPF_PINTOTASKBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,85,80,12 // disabled option kept for reference - LTEXT "Install shortcuts for:",IDC_SPF_FOLDERS,19,111,197,8 - CONTROL "&Current user only",IDC_SPF_PERSONAL,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,29,122,85,12 - CONTROL "&All users",IDC_SPF_COMMON,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,29,134,102,12 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 -END - -IDD_FINISH DIALOGEX 0, 0, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Confirm Your Selections" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Ready to Install",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Setup is now ready to begin installing %s on your computer.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - LTEXT "&Current settings:",-1,22,40,83,8 - EDITTEXT IDC_CYS_TEXT,22,50,284,106,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY - LTEXT "Click Install to continue with the installation, or click Back if you want to review or change any settings.",-1,22,160,278,16 -END - -IDD_UNINSTALL DIALOGEX 0, 0, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Uninstall" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Setup Status",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Please wait while Setup is removing previous version of application.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - LTEXT "File:",-1,22,46,23,8 - CONTROL "",IDC_PGS_FROM,"Static",SS_SIMPLE | SS_NOPREFIX,50,46,256,8 -END - -IDD_PROGRESS DIALOGEX 0, 0, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Progress" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "",IDC_WHITE_RECT,0,0,331,35,WS_CLIPCHILDREN | NOT WS_GROUP - LTEXT "Setup Status",IDC_BOLDWHITE_TEXT,12,8,89,8 - LTEXT "Please wait while Setup is copying files on your computer.",IDC_NORMALWHITE_TEXT,22,18,263,8 - CONTROL 111,IDC_INSTALL_ICON,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,290,0,36,36 - CONTROL "",-1,"Static",SS_ETCHEDHORZ | WS_GROUP,0,35,333,1 - LTEXT "From:",-1,22,46,22,8 - CONTROL "",IDC_PGS_FROM,"Static",SS_SIMPLE | SS_NOPREFIX,50,46,256,8 - LTEXT "To:",-1,22,60,22,8 - CONTROL "",IDC_PGS_TO,"Static",SS_SIMPLE | SS_NOPREFIX,50,60,256,8 - LTEXT "Total:",-1,22,83,24,8 - CONTROL "Progress1",IDC_PGS_PGS,"msctls_progress32",WS_BORDER,50,82,256,11 -END - -IDD_DONE DIALOGEX 0, 0, 330, 187 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPCHILDREN | WS_CAPTION -CAPTION "Finished" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Setup has finished installing %s on your computer. The application may be started by clicking on the installed shorcuts.",IDC_DONE_TEXT,13,13,198,25 - LTEXT "Click Finish to exit Setup.",-1,13,131,198,11 - CONTROL "&View Read Me",IDC_DONE_README,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,151,119,10 - CONTROL "&Launch %s",IDC_DONE_RUN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,166,223,10 -END - -IDD_COMMONCONTROL DIALOGEX 84, 53, 287, 107 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Setup" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Your version of COMCTL32.DLL is:",-1,6,40,116,8 - LTEXT "Text",IDC_CC_VERSION,123,40,60,8 - DEFPUSHBUTTON "OK",IDOK,118,87,50,14,WS_GROUP - LTEXT "You are using old version of a system library COMCTL32.DLL. Installed application",-1,6,7,277,8 - LTEXT "requires COMCTL32.DLL in version %d.%d or later.",IDC_CC_VERSION_NEED,6,15,277,8 - LTEXT "Please do not hesitate and install free available upgrade of COMCTL32.DLL library.",-1,6,23,277,8 - LTEXT "The latest version of COMCTL32.DLL download pages:",-1,6,57,201,8 - EDITTEXT -1,4,67,269,10,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP -END - -IDD_CF_OVERWRITE DIALOGEX 61, 53, 349, 89 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Confirm File Overwrite" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - RTEXT "Overwrite File:",-1,5,9,51,8 - LTEXT "fnTarget",IDC_CF_TARGETFILENAME,61,9,283,8 - LTEXT "attrTarget",IDC_CF_TARGETFILEATTR,61,20,283,8 - RTEXT "With File:",-1,5,39,51,8 - LTEXT "fnSource",IDC_CF_SOURCEFILENAME,61,39,283,8 - LTEXT "attrSource",IDC_CF_SOURCEFILEATTR,61,50,283,8 - DEFPUSHBUTTON "&Yes",IDOK,8,69,60,14 - PUSHBUTTON "&All",IDC_CF_YESALL,76,69,60,14 - PUSHBUTTON "&Skip",IDC_CF_SKIP,144,69,60,14 - PUSHBUTTON "S&kip All",IDC_CF_SKIPALL,212,69,60,14 - PUSHBUTTON "Cancel",IDCANCEL,280,69,60,14 -END - -IDD_CF_RETRY DIALOGEX 31, 84, 350, 86 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Error Creating File" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - RTEXT "Creating File:",-1,5,9,47,8 - LTEXT "fnName",IDC_CF_RETRYNAME,60,9,279,8 - RTEXT "Error:",-1,5,29,47,8 - LTEXT "fnError",IDC_CF_RETRYERROR,60,29,279,21 - PUSHBUTTON "&Retry",IDOK,43,64,60,14 - PUSHBUTTON "&Skip",IDC_CF_SKIP,111,64,60,14 - PUSHBUTTON "S&kip All",IDC_CF_SKIPALL,179,64,60,14 - PUSHBUTTON "Cancel",IDCANCEL,247,64,60,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_WZR_BACK "< &Back" - IDS_WZR_NEXT "&Next >" - IDS_WZR_EXIT "Cancel" - IDS_WZR_YES "&Yes" - IDS_WZR_NO "&No" - ERROR_CREATEWIZARD "Creation of Wizard dialog failed" - ERROR_LOADINF "Error accessing file: %s." - ERROR_LOADLICENSE "Error accessing license file." - IDS_INSTALLING "%s" - IDS_CHOOSEDIR "Choose Directory" - IDS_NODIR "The directory:\n\n'%s'\n\ndoes not exist. Do you want the directory to be created?" - IDS_NOSPACE "There is not enough space on disk %s\n\nspace required: %ld bytes\nspace available: %ld bytes\n\nPlease free up some disk space.\nPress Cancel to ignore this warning." - IDS_WZR_FINISH "&Finish" - IDS_TARGETDIR "Target directory" - IDS_PERSONAL "Shortcuts for current user only" -END - -STRINGTABLE -BEGIN - IDS_WZR_INSTALL "&Install" - IDS_INSTFAILED "Setup is not complete. Application %s is not installed.\n\nYou may run the Setup program at a later time to complete the installation." - ERROR_CMDLINE "Usage:\nSETUP [/?] [/s] [/d dest_dir] [/id ] [/is ] [/au ]\n\n[x] means that parameter x is optional.\n means that parameter y or n is required.\n\n/? -- Generates this Usage message.\n/s -- Silent unattended install.\n/d -- Destination directory.\n/id -- Install Desktop Shortcut.\n/is -- Install Start Menu Shortcut.\n/au -- All users common folders." - IDS_CONFLICTWITHNEWER "The directory '%s' already contains newer version of installed application.\n\nTo install to this directory, uninstall the existing Open Salamander. Then you can install this version of Open Salamander.\n\nOtherwise you can choose another directory." - IDS_INSTNEEDRESTART "Setup is not complete. Windows restart is needed to finish uninstalling shell extensions that are in use.\n\nPlease restart your Windows and run the Setup program again to complete the installation." - IDS_TARGETDIRUPGRADE "Target directory (Upgrade)" - IDS_CONFLICTPRIOR "The directory '%s' already contains a prior version of the installed application.\n\nPress OK to upgrade it.\nPress Cancel to install to another directory." - IDS_CONFLICTSAME "The directory '%s' already contains the same version of the installed application.\n\nPress OK to repair it.\nPress Cancel to install to another directory." - IDS_PREVIEWBUILDWARNING "This is PREVIEW BUILD of Open Salamander, released in Early Access Program. It should NOT be used in production environments. Use it for testing only. We are looking for your feedback at Early Access Program section .\nNote: this version is time limited." - IDS_BETAWARNING "This is BETA version of Open Salamander. It should NOT be used in production environments. Use it for testing purpose only. We are looking for your feedback .\nNote: this version is time limited." -END - -STRINGTABLE -BEGIN - IDS_COMMON "Shortcuts for all users" - IDS_INSERT_DESKTOP "Insert program shortcut to Desktop" - IDS_INSERT_MENU "Insert program shortcut in Start Menu" - IDS_INVALIDPATH "Destination directory '%s' is invalid." - IDS_NAMEUSEDFORFILE "The name ""%s"" has already been used for a file." - IDS_CREATEDIRFAILED "Unable to create new directory:\n%s" - IDS_ERRORCREATELOG "Creating log file %s failed." - IDS_APPRUNNING "Setup has detected that installed application is running.\nPlease close it and click OK to continue.\nApplication title is %s." - IDS_MAINWINDOWTITLE "Setup" - IDS_SETUPCOPYRIGHT1 "Copyright © 1997-2023 Taskscape Ltd" - IDS_INSTALL_STOP "Setup is not complete. If you quit now, the program will not be installed.\n\nYou may run the Setup program again at another time to complete the installation.\n\nExit Setup?" - IDS_INSTALL_STOP_TITLE "Exit Setup" - IDS_WIZ_TITLE "Setup - %s" -END - -STRINGTABLE -BEGIN - ERROR_CF_OPENFILE "Error opening file %s\n" - ERROR_CF_FILEINFORMATION "Error getting file informations %s\n" - ERROR_CF_CREATEFILE "Error creating file %s\n" - ERROR_CF_FILESETATTR "Error setting file attributes %s\n" - ERROR_CF_READFILE "Error reading file %s\n" - ERROR_CF_WRITEFILE "Error writing file %s\n" - ERROR_CF_GETATTR "Error getting file attributes: " - ERROR_DLGCREATE "Error creating dialog window: " -END - -STRINGTABLE -BEGIN - ERROR_CREATESHORTCUT "Error (%08X) creating shortcut %s\n" -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// -#define INSIDE_SETUP -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY) -#include "remove\resource.h" -LANGUAGE LANG_CZECH, SUBLANG_DEFAULT -#include "remove\remove_cz.rc2" -LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL -#include "remove\remove_de.rc2" -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#include "remove\remove_en.rc2" -#endif - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/src/vcxproj/salamand.sln b/src/vcxproj/salamand.sln index 83a0065a..6ad95e05 100644 --- a/src/vcxproj/salamand.sln +++ b/src/vcxproj/salamand.sln @@ -179,12 +179,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tserver", "tserver\tserver. EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfx7zip", "sfx7zip\sfx7zip.vcxproj", "{997B557B-4FB5-49FF-85AC-1FE66B9EBCFF}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "setup", "setup\setup.vcxproj", "{473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "translator", "translator\translator.vcxproj", "{C5833A09-5056-4C59-9E53-721A4D011936}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "remove", "setup\remove.vcxproj", "{D75FF963-62AA-4B33-ACFD-51616CB4FA65}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uncab", "..\plugins\uncab\vcxproj\uncab.vcxproj", "{3D197204-77AD-4B0D-B2E3-45A20CCF9140}" EndProject Global @@ -1072,18 +1068,6 @@ Global {997B557B-4FB5-49FF-85AC-1FE66B9EBCFF}.Utils (Release)|Win32.Build.0 = Release|Win32 {997B557B-4FB5-49FF-85AC-1FE66B9EBCFF}.Utils (Release)|x64.ActiveCfg = Release|Win32 {997B557B-4FB5-49FF-85AC-1FE66B9EBCFF}.Utils (Release)|x64.Build.0 = Release|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Debug|Win32.ActiveCfg = Debug|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Debug|Win32.Build.0 = Debug|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Debug|x64.ActiveCfg = Debug|x64 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Debug|x64.Build.0 = Debug|x64 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Release|Win32.ActiveCfg = Release|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Release|Win32.Build.0 = Release|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Release|x64.ActiveCfg = Release|x64 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Release|x64.Build.0 = Release|x64 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Utils (Release)|Win32.ActiveCfg = Release|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Utils (Release)|Win32.Build.0 = Release|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Utils (Release)|x64.ActiveCfg = Release|x64 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Utils (Release)|x64.Build.0 = Release|x64 {C5833A09-5056-4C59-9E53-721A4D011936}.Debug|Win32.ActiveCfg = Debug|Win32 {C5833A09-5056-4C59-9E53-721A4D011936}.Debug|Win32.Build.0 = Debug|Win32 {C5833A09-5056-4C59-9E53-721A4D011936}.Debug|x64.ActiveCfg = Debug|Win32 @@ -1096,18 +1080,6 @@ Global {C5833A09-5056-4C59-9E53-721A4D011936}.Utils (Release)|Win32.Build.0 = Release|Win32 {C5833A09-5056-4C59-9E53-721A4D011936}.Utils (Release)|x64.ActiveCfg = Release|Win32 {C5833A09-5056-4C59-9E53-721A4D011936}.Utils (Release)|x64.Build.0 = Release|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Debug|Win32.ActiveCfg = Debug|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Debug|Win32.Build.0 = Debug|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Debug|x64.ActiveCfg = Debug|x64 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Debug|x64.Build.0 = Debug|x64 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Release|Win32.ActiveCfg = Release|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Release|Win32.Build.0 = Release|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Release|x64.ActiveCfg = Release|x64 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Release|x64.Build.0 = Release|x64 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Utils (Release)|Win32.ActiveCfg = Release|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Utils (Release)|Win32.Build.0 = Release|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Utils (Release)|x64.ActiveCfg = Release|x64 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Utils (Release)|x64.Build.0 = Release|x64 {3D197204-77AD-4B0D-B2E3-45A20CCF9140}.Debug|Win32.ActiveCfg = Debug|Win32 {3D197204-77AD-4B0D-B2E3-45A20CCF9140}.Debug|Win32.Build.0 = Debug|Win32 {3D197204-77AD-4B0D-B2E3-45A20CCF9140}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/src/vcxproj/setup/remove.vcxproj b/src/vcxproj/setup/remove.vcxproj deleted file mode 100644 index 1f707d8e..00000000 --- a/src/vcxproj/setup/remove.vcxproj +++ /dev/null @@ -1,127 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - 16.0 - remove - {D75FF963-62AA-4B33-ACFD-51616CB4FA65} - Remove - 10.0 - - - - Application - false - v143 - - - Application - true - v143 - - - Application - false - v143 - - - Application - true - v143 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\..\common;..\..\common\dep;%(AdditionalIncludeDirectories);$(_ZVcpkgCurrentInstalledDir)include - - - - - ..\..\common;..\..\common\dep;%(AdditionalIncludeDirectories);$(_ZVcpkgCurrentInstalledDir)include - - - - - ..\..\common;..\..\common\dep;%(AdditionalIncludeDirectories);$(_ZVcpkgCurrentInstalledDir)include - - - - - ..\..\common;..\..\common\dep;%(AdditionalIncludeDirectories);$(_ZVcpkgCurrentInstalledDir)include - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/vcxproj/setup/remove.vcxproj.filters b/src/vcxproj/setup/remove.vcxproj.filters deleted file mode 100644 index e3af3ef5..00000000 --- a/src/vcxproj/setup/remove.vcxproj.filters +++ /dev/null @@ -1,52 +0,0 @@ - - - - - {a5f28ac7-1781-48dc-94ab-b10ca3c32620} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {2e41fee9-302b-48a5-a742-4fdad5620e3f} - ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - - - - - - - - - - Resource Files - - - - - Source Files - - - \ No newline at end of file diff --git a/src/vcxproj/setup/remove_base.props b/src/vcxproj/setup/remove_base.props deleted file mode 100644 index f10a6c79..00000000 --- a/src/vcxproj/setup/remove_base.props +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - $(OPENSAL_BUILD_DIR)$(ProjectName)\$(Configuration)_$(ShortPlatform)\ - $(OutDir)Intermediate\ - false - - - - WIN32;_WINDOWS;WINVER=0x0601;_WIN32_IE=0x0601;_WIN32_WINNT=0x0601;%(PreprocessorDefinitions) - Use - precomp.h - $(IntDir)remove.pch - Level3 - true - stdcpp17 - - - $(OutDir)remove.exe - true - $(OutDir)remove.pdb - Windows - - - WINVER=0x0601;%(PreprocessorDefinitions) - 0x0409 - - - - diff --git a/src/vcxproj/setup/remove_debug.props b/src/vcxproj/setup/remove_debug.props deleted file mode 100644 index 6a66ea83..00000000 --- a/src/vcxproj/setup/remove_debug.props +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - true - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebug - - - true - - - _DEBUG;%(PreprocessorDefinitions) - - - - diff --git a/src/vcxproj/setup/remove_release.props b/src/vcxproj/setup/remove_release.props deleted file mode 100644 index c733df78..00000000 --- a/src/vcxproj/setup/remove_release.props +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - false - - - - NDEBUG;%(PreprocessorDefinitions) - MinSpace - MultiThreaded - true - - - true - true - - - NDEBUG;%(PreprocessorDefinitions) - - - call ..\..\..\tools\codesign\sign_with_retry.cmd "$(TargetPath)" - - - - diff --git a/src/vcxproj/setup/setup.sln b/src/vcxproj/setup/setup.sln deleted file mode 100644 index 68009721..00000000 --- a/src/vcxproj/setup/setup.sln +++ /dev/null @@ -1,46 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29001.49 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Setup", "setup.vcxproj", "{473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Remove", "remove.vcxproj", "{D75FF963-62AA-4B33-ACFD-51616CB4FA65}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F5178B19-4623-4C59-888A-4BF07C6C3BCB}" - ProjectSection(SolutionItems) = preProject - ..\.editorconfig = ..\.editorconfig - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Debug|Win32.ActiveCfg = Debug|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Debug|Win32.Build.0 = Debug|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Debug|x64.ActiveCfg = Debug|x64 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Debug|x64.Build.0 = Debug|x64 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Release|Win32.ActiveCfg = Release|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Release|Win32.Build.0 = Release|Win32 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Release|x64.ActiveCfg = Release|x64 - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9}.Release|x64.Build.0 = Release|x64 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Debug|Win32.ActiveCfg = Debug|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Debug|Win32.Build.0 = Debug|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Debug|x64.ActiveCfg = Debug|x64 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Debug|x64.Build.0 = Debug|x64 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Release|Win32.ActiveCfg = Release|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Release|Win32.Build.0 = Release|Win32 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Release|x64.ActiveCfg = Release|x64 - {D75FF963-62AA-4B33-ACFD-51616CB4FA65}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {93E1A5B8-A210-4056-ACE7-94F47046C8E6} - EndGlobalSection -EndGlobal diff --git a/src/vcxproj/setup/setup.vcxproj b/src/vcxproj/setup/setup.vcxproj deleted file mode 100644 index 809a093a..00000000 --- a/src/vcxproj/setup/setup.vcxproj +++ /dev/null @@ -1,137 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - 16.0 - setup - {473B82C6-D658-4D5D-B0EB-8A449B3DCDA9} - Setup - 10.0 - - - - Application - true - v143 - - - Application - false - v143 - - - Application - true - v143 - - - Application - false - v143 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\..\common;..\..\common\dep;%(AdditionalIncludeDirectories);$(_ZVcpkgCurrentInstalledDir)include - - - - - ..\..\common;..\..\common\dep;%(AdditionalIncludeDirectories);$(_ZVcpkgCurrentInstalledDir)include - - - - - ..\..\common;..\..\common\dep;%(AdditionalIncludeDirectories);$(_ZVcpkgCurrentInstalledDir)include - - - - - ..\..\common;..\..\common\dep;%(AdditionalIncludeDirectories);$(_ZVcpkgCurrentInstalledDir)include - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/vcxproj/setup/setup.vcxproj.filters b/src/vcxproj/setup/setup.vcxproj.filters deleted file mode 100644 index f813c91e..00000000 --- a/src/vcxproj/setup/setup.vcxproj.filters +++ /dev/null @@ -1,97 +0,0 @@ - - - - - {afc2cf40-0fd8-4a6b-8371-6c942c958d50} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {500fc5a9-3794-4003-8635-b465e884f175} - h;hpp;hxx;hm;inl - - - {8761b1db-66c1-47ad-b679-beea5521fb9a} - ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - {b073f170-f89b-407d-8c27-2dc08f2c3bbe} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - - - - Resource Files - - - Resource Files - - - Resource Files - - - - - Source Files - - - \ No newline at end of file diff --git a/src/vcxproj/setup/setup_base.props b/src/vcxproj/setup/setup_base.props deleted file mode 100644 index f0656a5a..00000000 --- a/src/vcxproj/setup/setup_base.props +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - $(OPENSAL_BUILD_DIR)$(ProjectName)\$(Configuration)_$(ShortPlatform)\ - $(OutDir)Intermediate\ - false - - - - WIN32;_WINDOWS;INSIDE_SETUP;WINVER=0x0601;_WIN32_IE=0x0601;_WIN32_WINNT=0x0601;%(PreprocessorDefinitions) - Use - precomp.h - $(IntDir)setup.pch - Level3 - true - stdcpp17 - - - $(OutDir)setup.exe - true - $(OutDir)setup.pdb - Windows - - - WINVER=0x0601;%(PreprocessorDefinitions) - 0x0409 - - - - diff --git a/src/vcxproj/setup/setup_debug.props b/src/vcxproj/setup/setup_debug.props deleted file mode 100644 index 6a66ea83..00000000 --- a/src/vcxproj/setup/setup_debug.props +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - true - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebug - - - true - - - _DEBUG;%(PreprocessorDefinitions) - - - - diff --git a/src/vcxproj/setup/setup_release.props b/src/vcxproj/setup/setup_release.props deleted file mode 100644 index c733df78..00000000 --- a/src/vcxproj/setup/setup_release.props +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - false - - - - NDEBUG;%(PreprocessorDefinitions) - MinSpace - MultiThreaded - true - - - true - true - - - NDEBUG;%(PreprocessorDefinitions) - - - call ..\..\..\tools\codesign\sign_with_retry.cmd "$(TargetPath)" - - - - diff --git a/src/vcxproj/setup/x64.props b/src/vcxproj/setup/x64.props deleted file mode 100644 index 400e8f0b..00000000 --- a/src/vcxproj/setup/x64.props +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - x64 - - - - _WIN64;%(PreprocessorDefinitions) - - - - - $(ShortPlatform) - - - diff --git a/src/vcxproj/setup/x86.props b/src/vcxproj/setup/x86.props deleted file mode 100644 index 647386b1..00000000 --- a/src/vcxproj/setup/x86.props +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - x86 - - - - $(ShortPlatform) - - - diff --git a/tools/Create-Sfx.ps1 b/tools/Create-Sfx.ps1 deleted file mode 100644 index 34d62e2a..00000000 --- a/tools/Create-Sfx.ps1 +++ /dev/null @@ -1,226 +0,0 @@ -<# -.SYNOPSIS -Creates a self-extracting executable (SFX) from a specified directory. - -.DESCRIPTION -The script compiles a minimal C# stub, packs files from the source directory, -and combines them into a single .exe file. It AUTOMATICALLY includes -the 'toolbars' directory from 'src\res\toolbars'. - -.PARAMETER SourceDir -Directory containing installer files (must include setup.exe). - -.PARAMETER OutputPath -Path to the output .exe file. - -.EXAMPLE -.\Create-Sfx.ps1 -SourceDir "Instalator" -OutputPath "Instalator_SFX.exe" -#> -param( - [Parameter(Mandatory=$true)] - [string]$SourceDir, - - [Parameter(Mandatory=$true)] - [string]$OutputPath -) - -$ErrorActionPreference = "Stop" - -# Check if source directory exists -if (-not (Test-Path $SourceDir)) { - Write-Error "Source directory '$SourceDir' does not exist." -} - -# Determine path to 'src\res\toolbars' relative to this script script location -$ScriptRoot = Split-Path $MyInvocation.MyCommand.Path -$ToolbarsSrcPath = Join-Path $ScriptRoot "..\src\res\toolbars" - -# Normalize path -if (Test-Path $ToolbarsSrcPath) { - # Resolve-Path returns a PathInfo object, so we specifically ask for the .Path string property - $ToolbarsSrcPath = (Resolve-Path $ToolbarsSrcPath).Path -} else { - Write-Warning "Toolbars directory not found at: $ToolbarsSrcPath. It will not be included." - $ToolbarsSrcPath = $null -} - -# --- 1. C# Code for the Stub --- -$csharpSource = @" -using System; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Reflection; -using System.Threading; - -[assembly: AssemblyTitle("SFX Installer")] -[assembly: AssemblyProduct("SFX Installer")] -[assembly: AssemblyVersion("1.0.0.0")] - -namespace SfxStub -{ - class Program - { - static void Main(string[] args) - { - string tempDir = Path.Combine(Path.GetTempPath(), "Install_" + Guid.NewGuid().ToString("N")); - string currentExe = Process.GetCurrentProcess().MainModule.FileName; - - try - { - // -- Step 1: Read ZIP Data -- - byte[] zipData; - using (var fs = new FileStream(currentExe, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - if (fs.Length < 8) return; - - // Read offset (last 8 bytes) - fs.Seek(-8, SeekOrigin.End); - long zipStartOffset; - using (var br = new BinaryReader(fs, System.Text.Encoding.Default, true)) - { - zipStartOffset = br.ReadInt64(); - } - - // Calculate ZIP length (File Length - Start Offset - 8 bytes footer) - long zipLength = fs.Length - zipStartOffset - 8; - - if (zipLength <= 0) - { - throw new Exception("Invalid SFX file structure."); - } - - // Load ONLY ZIP data into memory - zipData = new byte[zipLength]; - fs.Seek(zipStartOffset, SeekOrigin.Begin); - fs.Read(zipData, 0, (int)zipLength); - } - - // -- Step 2: Extract -- - // Console.WriteLine("Extracting..."); - Directory.CreateDirectory(tempDir); - - using (var ms = new MemoryStream(zipData)) - using (var archive = new ZipArchive(ms, ZipArchiveMode.Read)) - { - archive.ExtractToDirectory(tempDir); - } - - // -- Step 3: Run setup.exe -- - string setupExe = Path.Combine(tempDir, "setup.exe"); - - if (!File.Exists(setupExe)) - { - string[] exeFiles = Directory.GetFiles(tempDir, "*.exe"); - if (exeFiles.Length > 0) setupExe = exeFiles[0]; - else throw new FileNotFoundException("setup.exe not found."); - } - - ProcessStartInfo psi = new ProcessStartInfo(setupExe); - psi.WorkingDirectory = tempDir; - if (args.Length > 0) { - psi.Arguments = string.Join(" ", args); - } - - Process p = Process.Start(psi); - if (p != null) p.WaitForExit(); - } - catch (Exception ex) - { - Console.WriteLine("Error: " + ex.Message); - Console.WriteLine("Press any key to exit..."); - Console.ReadKey(); - } - finally - { - // -- Step 4: Cleanup -- - try - { - if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); - } - catch { } - } - } - } -} -"@ - -# --- 2. Compile Stub --- -$stubPath = Join-Path $env:TEMP "sfx_stub.exe" -Write-Host "Compiling C# code..." -ForegroundColor Cyan - -$assemblies = @("System.IO.Compression", "System.IO.Compression.FileSystem") - -try { - Add-Type -TypeDefinition $csharpSource -OutputAssembly $stubPath -OutputType ConsoleApplication -ReferencedAssemblies $assemblies -} -catch { - Write-Error "Compilation error. Ensure .NET Framework is installed." -} - -# --- 3. Pack Files --- -$tempZip = [System.IO.Path]::GetTempFileName() -if (Test-Path $tempZip) { Remove-Item $tempZip } -$tempZip = $tempZip + ".zip" - -# Create a staging directory to combine SourceDir and Toolbars -$stagingDir = Join-Path $env:TEMP ("sfx_stage_" + [Guid]::NewGuid().ToString("N")) -New-Item -ItemType Directory -Path $stagingDir | Out-Null - -try { - Write-Host "Preparing files in staging area..." -ForegroundColor Cyan - - # Copy SourceDir content - Copy-Item -Path "$SourceDir\*" -Destination $stagingDir -Recurse -Force - - # Copy Toolbars (Hardcoded) - if ($ToolbarsSrcPath) { - $destPath = Join-Path $stagingDir "toolbars" - Write-Host "Auto-including toolbars from: $ToolbarsSrcPath" -ForegroundColor Cyan - - # Explicitly create destination directory - if (-not (Test-Path $destPath)) { - New-Item -ItemType Directory -Path $destPath | Out-Null - } - - # Copy CONTENT of toolbars into destPath - Copy-Item -Path "$ToolbarsSrcPath\*" -Destination $destPath -Recurse -Force - } - - Write-Host "Compressing contents of staging area:" -ForegroundColor Yellow - # List files relative to staging dir so user sees structure - Get-ChildItem -Path $stagingDir -Recurse | Select-Object -ExpandProperty FullName | ForEach-Object { $_.Substring($stagingDir.Length) } - - Write-Host "`nCompressing..." -ForegroundColor Cyan - Compress-Archive -Path "$stagingDir\*" -DestinationPath $tempZip -CompressionLevel Optimal -} -finally { - # Cleanup staging dir - if (Test-Path $stagingDir) { Remove-Item $stagingDir -Recurse -Force } -} - -# --- 4. Combine (Stub + Zip + Offset) --- -Write-Host "Creating output file: $OutputPath" -ForegroundColor Cyan - -try { - $stubBytes = [System.IO.File]::ReadAllBytes($stubPath) - $zipBytes = [System.IO.File]::ReadAllBytes($tempZip) - - $offset = $stubBytes.Length - $offsetBytes = [System.BitConverter]::GetBytes([long]$offset) - - $fs = [System.IO.File]::Create($OutputPath) - $fs.Write($stubBytes, 0, $stubBytes.Length) - $fs.Write($zipBytes, 0, $zipBytes.Length) - $fs.Write($offsetBytes, 0, $offsetBytes.Length) - $fs.Close() - - Write-Host "Done! Created: $OutputPath" -ForegroundColor Green -} -catch { - Write-Error "Error combining files: $_ " -} -finally { - if (Test-Path $stubPath) { Remove-Item $stubPath } - if (Test-Path $tempZip) { Remove-Item $tempZip } -} \ No newline at end of file diff --git a/tools/prepare_installer.ps1 b/tools/prepare_installer.ps1 index 1cc50058..43bf54bd 100644 --- a/tools/prepare_installer.ps1 +++ b/tools/prepare_installer.ps1 @@ -1,21 +1,22 @@ param( [string]$BuildDir = "build_stage", [string]$StagingDir = "Installer_Staging", - [string]$OutputPath = "OpenSalamander_v5.exe" + [string]$BuildNumber = "0" ) +Write-Host "=== Open Salamander Installer Staging Script ===" -ForegroundColor Cyan +Write-Host "Staging files for Inno Setup..." + if (Test-Path $StagingDir) { Remove-Item $StagingDir -Recurse -Force } -New-Item -ItemType Directory -Path $StagingDir -New-Item -ItemType Directory -Path "$StagingDir\plugins" -New-Item -ItemType Directory -Path "$StagingDir\lang" -New-Item -ItemType Directory -Path "$StagingDir\convert" -New-Item -ItemType Directory -Path "$StagingDir\toolbars" -New-Item -ItemType Directory -Path "$StagingDir\utils" - -# 1. Copy base installer files -Copy-Item "Installer\setup.exe" "$StagingDir\" -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Path $StagingDir | Out-Null +New-Item -ItemType Directory -Path "$StagingDir\plugins" | Out-Null +New-Item -ItemType Directory -Path "$StagingDir\lang" | Out-Null +New-Item -ItemType Directory -Path "$StagingDir\convert" | Out-Null +New-Item -ItemType Directory -Path "$StagingDir\toolbars" | Out-Null +New-Item -ItemType Directory -Path "$StagingDir\utils" | Out-Null + +# 1. Copy license file Copy-Item "Installer\LICENSE" "$StagingDir\" -ErrorAction SilentlyContinue -Copy-Item "Installer\x64" "$StagingDir\" -ErrorAction SilentlyContinue # 2. Copy main executables and DLLs function Copy-Exe($srcPatterns, $fileName, $dest) { @@ -23,7 +24,7 @@ function Copy-Exe($srcPatterns, $fileName, $dest) { $found = Get-ChildItem -Path $pattern -ErrorAction SilentlyContinue | Select-Object -First 1 if ($found) { Copy-Item $found.FullName $dest - Write-Host "Found $fileName at: $($found.FullName)" + Write-Host "Found $fileName at: $($found.FullName)" -ForegroundColor Green return $true } } @@ -31,7 +32,7 @@ function Copy-Exe($srcPatterns, $fileName, $dest) { $found = Get-ChildItem -Path $BuildDir, "src" -Filter $fileName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 if ($found) { Copy-Item $found.FullName $dest - Write-Host "Found $fileName (recursive) at: $($found.FullName)" + Write-Host "Found $fileName (recursive) at: $($found.FullName)" -ForegroundColor Green return $true } Write-Warning "$fileName not found in primary locations or recursively." @@ -41,11 +42,9 @@ function Copy-Exe($srcPatterns, $fileName, $dest) { # Main exes $salamandCopied = Copy-Exe @("$BuildDir\Release_x64\salamand.exe", "src\vcxproj\salamander\Release_x64\salamand.exe") "salamand.exe" "$StagingDir\" $salmonCopied = Copy-Exe @("$BuildDir\Release_x64\salmon.exe", "src\vcxproj\salmon\salamander\Release_x64\utils\salmon.exe") "salmon.exe" "$StagingDir\" -$removeCopied = Copy-Exe @("$BuildDir\Release_x64\remove.exe", "src\vcxproj\setup\remove\Release_x64\remove.exe") "remove.exe" "$StagingDir\" if (-not $salamandCopied) { Write-Error "Could not find salamand.exe" } if (-not $salmonCopied) { Write-Error "Could not find salmon.exe" } -if (-not $removeCopied) { Write-Error "Could not find remove.exe" } # Shell extensions Copy-Exe @("$BuildDir\Release_x64\salextx64.dll", "$BuildDir\shellext\Release_x64\salextx64.dll", "src\vcxproj\shellext\salamander\Release_x64\plugins\Intermediate\salextx64\salextx64.dll", "src\vcxproj\shellext\salamander\Release_x64\salextx64.dll") "salextx64.dll" "$StagingDir\" @@ -53,6 +52,14 @@ Copy-Exe @("$BuildDir\Release_Win32\salextx86.dll", "$BuildDir\shellext\Release_ # Utils Copy-Exe @("$BuildDir\Release_x64\salpvenv.exe") "salpvenv.exe" "$StagingDir\" +Copy-Exe @("$BuildDir\Release_x64\salopen.exe") "salopen.exe" "$StagingDir\" +Copy-Exe @("$BuildDir\Release_x64\salspawn.exe") "salspawn.exe" "$StagingDir\" +Copy-Exe @("$BuildDir\Release_x64\tserver.exe", "$BuildDir\Release_Win32\tserver.exe") "tserver.exe" "$StagingDir\" +Copy-Exe @("$BuildDir\Release_x64\sfx7zip.exe", "$BuildDir\Release_Win32\sfx7zip.exe") "sfx7zip.exe" "$StagingDir\" +Copy-Exe @("$BuildDir\Release_x64\zip2sfx.exe", "$BuildDir\Release_Win32\zip2sfx.exe") "zip2sfx.exe" "$StagingDir\" +Copy-Exe @("$BuildDir\Release_x64\translator.exe", "$BuildDir\Release_Win32\translator.exe") "translator.exe" "$StagingDir\" +Copy-Exe @("$BuildDir\Release_x64\fcremote.exe") "fcremote.exe" "$StagingDir\" +Copy-Exe @("$BuildDir\Release_x64\7zwrapper.exe") "7zwrapper.exe" "$StagingDir\" # OpenSSL $opensslCopied1 = Copy-Exe @("utils\libeay32.dll", "external\openssl\libeay32.dll", "libeay32.dll") "libeay32.dll" "$StagingDir\utils\" @@ -84,7 +91,7 @@ foreach ($file in $splFiles) { $pluginName = $file.BaseName $pluginDestDir = New-Item -ItemType Directory -Path "$StagingDir\plugins\$pluginName" -Force Copy-Item $file.FullName "$pluginDestDir\" - Write-Host "Found plugin $pluginName at: $($file.FullName)" + Write-Host "Found plugin $pluginName at: $($file.FullName)" -ForegroundColor Green $stagedLangDir = $null Get-ChildItem -Path $file.DirectoryName -Filter "*.slg" -Recurse | @@ -93,69 +100,10 @@ foreach ($file in $splFiles) { $stagedLangDir = New-Item -ItemType Directory -Path "$pluginDestDir\lang" -Force } Copy-Item $_.FullName "$stagedLangDir\" - Write-Host " Found lang file: $($_.Name)" + Write-Host " Found lang file: $($_.Name)" -ForegroundColor Gray } } -# 7. Generate setup.inf -$setupInf = @" -[Private] -ApplicationName=Open Salamander 5.0 -ApplicationNameVer=Open Salamander 5.0 -DefaultDirectory=%4%\Open Salamander 5.0 -LicenseFile=LICENSE -SkipChooseDirectory=0 -SaveRemoveLog=%1%\uninstall.log -UninstallRunProgramQuietPath=%1%\remove.exe - -[CopyFiles] -salamand.exe,%1\salamand.exe,0 -salmon.exe,%1\salmon.exe,0 -remove.exe,%1\remove.exe,0 -"@ - -function Add-FileToSetupInf($fileRelPath) { - $script:setupInf += "`n$fileRelPath,%1\$fileRelPath,0" -} - -$rootFiles = @("salextx64.dll", "salextx86.dll", "salopen.exe", "salspawn.exe", "tserver.exe", "sfx7zip.exe", "zip2sfx.exe", "salpvenv.exe", "translator.exe") -foreach ($rf in $rootFiles) { - if (Test-Path "$StagingDir\$rf") { - Add-FileToSetupInf $rf - } -} - -function Add-ToSetupInf($path) { - if (Test-Path "$StagingDir\$path") { - $files = Get-ChildItem -Path "$StagingDir\$path" -File -Recurse - foreach ($f in $files) { - $relPath = $f.FullName.Substring((Get-Item $StagingDir).FullName.Length + 1) - if ($relPath -notmatch "\\Intermediate\\") { - Add-FileToSetupInf $relPath - } - } - } -} - -Add-ToSetupInf "lang" -Add-ToSetupInf "convert" -Add-ToSetupInf "toolbars" -Add-ToSetupInf "plugins" -Add-ToSetupInf "utils" - -$setupInf += @" - -[CreateShortcuts] -0,Open Salamander 5.0,%1\salamand.exe, -1,Open Salamander 5.0,%1\salamand.exe, -"@ - -$setupInf | Out-File -FilePath "$StagingDir\setup.inf" -Encoding utf8 - -# 8. Create SFX using the existing tool -$ScriptRoot = Split-Path $MyInvocation.MyCommand.Path -$SfxTool = Join-Path $ScriptRoot "Create-Sfx.ps1" - -powershell.exe -File "$SfxTool" -SourceDir "$StagingDir" -OutputPath "$OutputPath" - -Write-Host "Installer created: $OutputPath" +Write-Host "`n=== Staging Complete ===" -ForegroundColor Cyan +Write-Host "Files staged in: $StagingDir" +Write-Host "Ready for Inno Setup compilation." From 7d3c67c66c3509caa94d8178035583322b103b09 Mon Sep 17 00:00:00 2001 From: Maciej Zagozda Date: Fri, 27 Mar 2026 15:45:52 +0100 Subject: [PATCH 2/6] Fixed build error --- src/common/handles.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/common/handles.cpp b/src/common/handles.cpp index 25b71929..7b158109 100644 --- a/src/common/handles.cpp +++ b/src/common/handles.cpp @@ -2219,9 +2219,12 @@ C__Handles::LoadLibraryUtf8(LPCSTR lpLibFileName) else { ret = ::LoadLibraryW(fileNameW); - free(fileNameW); } - CheckCreate(ret != NULL, __htLibrary, __hoLoadLibrary, ret, GetLastError(), TRUE, lpLibFileName); + DWORD err = GetLastError(); + CheckCreate(ret != NULL, __htLibrary, __hoLoadLibrary, ret, err, TRUE, NULL, lpLibFileName, fileNameW); + SetLastError(err); + if (fileNameW != NULL) + free(fileNameW); return ret; } From 71a39294780607d058582188abee5e85b7f34727 Mon Sep 17 00:00:00 2001 From: Maciej Zagozda Date: Fri, 27 Mar 2026 15:51:19 +0100 Subject: [PATCH 3/6] Improved installer process --- Installer/setup.iss | 17 +++++++---------- README.md | 2 +- tools/prepare_installer.ps1 | 7 +++++++ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Installer/setup.iss b/Installer/setup.iss index 294d9bfb..0dbcba10 100644 --- a/Installer/setup.iss +++ b/Installer/setup.iss @@ -77,6 +77,9 @@ Source: "{#SourcePath}\utils\ssleay32.dll"; DestDir: "{app}\utils"; Flags: ignor ; License file Source: "{#SourcePath}\LICENSE"; DestDir: "{app}"; Flags: ignoreversion +; Build info for traceability +Source: "{#SourcePath}\build_info.txt"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist + ; Language files for main application Source: "{#SourcePath}\lang\*.slg"; DestDir: "{app}\lang"; Flags: ignoreversion @@ -118,23 +121,17 @@ Type: dirifempty; Name: "{app}" [Code] // Check if Open Salamander is currently running and offer to close it function InitializeSetup(): Boolean; -var - ResultCode: Integer; begin Result := True; - // Check if salamand.exe is running - if CheckForMutexes('OpenSalamanderMutex') then + // Check if salamand.exe is running (uses process list mutex from src/tasklist.cpp) + while CheckForMutexes('TaskscapeLtdSalamander3bProcessListMutex') do begin if MsgBox('Open Salamander is currently running. Please close it before continuing installation.' + #13#10 + #13#10 + 'Click OK to retry or Cancel to exit setup.', mbError, MB_OKCANCEL) = IDCANCEL then begin Result := False; - end - else - begin - // Retry the check - Result := InitializeSetup(); + Exit; end; end; end; @@ -144,7 +141,7 @@ function InitializeUninstall(): Boolean; begin Result := True; - if CheckForMutexes('OpenSalamanderMutex') then + if CheckForMutexes('TaskscapeLtdSalamander3bProcessListMutex') then begin MsgBox('Open Salamander is currently running. Please close it before uninstalling.', mbError, MB_OK); Result := False; diff --git a/README.md b/README.md index e3d90c67..5018f3ca 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ The repository includes a GitHub Actions workflow (`.github\workflows\build-inst 4. Compiles the installer with build number versioning 5. Creates a GitHub release with the installer attached -The workflow is triggered on pushes to `master` and produces versioned installers named `OpenSalamander_5.0.{build_number}.exe`. +The workflow is triggered on pushes to `main` and produces versioned installers named `OpenSalamander_5.0.{build_number}.exe`. ## Customization diff --git a/tools/prepare_installer.ps1 b/tools/prepare_installer.ps1 index 43bf54bd..8cbfc7d5 100644 --- a/tools/prepare_installer.ps1 +++ b/tools/prepare_installer.ps1 @@ -5,6 +5,7 @@ param( ) Write-Host "=== Open Salamander Installer Staging Script ===" -ForegroundColor Cyan +Write-Host "Build Number: $BuildNumber" -ForegroundColor Cyan Write-Host "Staging files for Inno Setup..." if (Test-Path $StagingDir) { Remove-Item $StagingDir -Recurse -Force } @@ -15,6 +16,12 @@ New-Item -ItemType Directory -Path "$StagingDir\convert" | Out-Null New-Item -ItemType Directory -Path "$StagingDir\toolbars" | Out-Null New-Item -ItemType Directory -Path "$StagingDir\utils" | Out-Null +# Write build info file for traceability +@" +Build Number: $BuildNumber +Build Date: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss UTC" -AsUTC) +"@ | Out-File -FilePath "$StagingDir\build_info.txt" -Encoding utf8 + # 1. Copy license file Copy-Item "Installer\LICENSE" "$StagingDir\" -ErrorAction SilentlyContinue From c05740cbf83108cd5b8993c5cef6cd58ff3d7900 Mon Sep 17 00:00:00 2001 From: Maciej Zagozda Date: Fri, 27 Mar 2026 18:22:02 +0100 Subject: [PATCH 4/6] Improved installer process --- src/vcxproj/salamand.sln | 12 ------------ tools/prepare_installer.ps1 | 3 +-- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/vcxproj/salamand.sln b/src/vcxproj/salamand.sln index 6ad95e05..ab887a04 100644 --- a/src/vcxproj/salamand.sln +++ b/src/vcxproj/salamand.sln @@ -162,8 +162,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "7zwrapper", "..\plugins\7zi EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fcremote", "..\plugins\filecomp\vcxproj\fcremote\fcremote.vcxproj", "{89CD2440-2844-4C0B-9CDE-1045334E9EC0}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "salpvenv", "..\plugins\pictview\vcxproj\salpvenv.vcxproj", "{17CF5E05-F29C-4E5D-BA41-83254E342E0B}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlite", "sqlite\sqlite.vcxproj", "{49D6CEED-804F-4EA6-BD12-2D825E13DAE3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lang_portables", "..\plugins\portables\vcxproj\lang_portables.vcxproj", "{3F2F1440-A2C9-47F0-BE4E-3E2794BEDF07}" @@ -1004,16 +1002,6 @@ Global {89CD2440-2844-4C0B-9CDE-1045334E9EC0}.Release|x64.Build.0 = Release|x64 {89CD2440-2844-4C0B-9CDE-1045334E9EC0}.Utils (Release)|Win32.ActiveCfg = Release|Win32 {89CD2440-2844-4C0B-9CDE-1045334E9EC0}.Utils (Release)|x64.ActiveCfg = Release|x64 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Debug|Win32.ActiveCfg = Debug|Win32 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Debug|Win32.Build.0 = Debug|Win32 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Debug|x64.ActiveCfg = Debug|Win32 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Debug|x64.Build.0 = Debug|Win32 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Release|Win32.ActiveCfg = Release|Win32 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Release|Win32.Build.0 = Release|Win32 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Release|x64.ActiveCfg = Release|Win32 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Release|x64.Build.0 = Release|Win32 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Utils (Release)|Win32.ActiveCfg = Release|Win32 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Utils (Release)|x64.ActiveCfg = Release|Win32 {49D6CEED-804F-4EA6-BD12-2D825E13DAE3}.Debug|Win32.ActiveCfg = Debug|Win32 {49D6CEED-804F-4EA6-BD12-2D825E13DAE3}.Debug|Win32.Build.0 = Debug|Win32 {49D6CEED-804F-4EA6-BD12-2D825E13DAE3}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/tools/prepare_installer.ps1 b/tools/prepare_installer.ps1 index 8cbfc7d5..86e6c740 100644 --- a/tools/prepare_installer.ps1 +++ b/tools/prepare_installer.ps1 @@ -57,8 +57,7 @@ if (-not $salmonCopied) { Write-Error "Could not find salmon.exe" } Copy-Exe @("$BuildDir\Release_x64\salextx64.dll", "$BuildDir\shellext\Release_x64\salextx64.dll", "src\vcxproj\shellext\salamander\Release_x64\plugins\Intermediate\salextx64\salextx64.dll", "src\vcxproj\shellext\salamander\Release_x64\salextx64.dll") "salextx64.dll" "$StagingDir\" Copy-Exe @("$BuildDir\Release_Win32\salextx86.dll", "$BuildDir\shellext\Release_Win32\salextx86.dll", "$BuildDir\Release_x64\salextx86.dll", "src\vcxproj\shellext\salamander\Release_x86\plugins\Intermediate\salextx86\salextx86.dll", "src\vcxproj\shellext\salamander\Release_x86\salextx86.dll") "salextx86.dll" "$StagingDir\" -# Utils -Copy-Exe @("$BuildDir\Release_x64\salpvenv.exe") "salpvenv.exe" "$StagingDir\" +# Utils (Note: salpvenv.exe excluded - depends on proprietary PVW32Cnv.lib) Copy-Exe @("$BuildDir\Release_x64\salopen.exe") "salopen.exe" "$StagingDir\" Copy-Exe @("$BuildDir\Release_x64\salspawn.exe") "salspawn.exe" "$StagingDir\" Copy-Exe @("$BuildDir\Release_x64\tserver.exe", "$BuildDir\Release_Win32\tserver.exe") "tserver.exe" "$StagingDir\" From 4e72e202bf505f0d65bf6c2a2a4a4ad9dd052812 Mon Sep 17 00:00:00 2001 From: Maciej Zagozda Date: Fri, 27 Mar 2026 18:32:21 +0100 Subject: [PATCH 5/6] Improved installer process --- src/plugins/pictview/vcxproj/pictview.vcxproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/plugins/pictview/vcxproj/pictview.vcxproj b/src/plugins/pictview/vcxproj/pictview.vcxproj index ec856bc0..82f30371 100644 --- a/src/plugins/pictview/vcxproj/pictview.vcxproj +++ b/src/plugins/pictview/vcxproj/pictview.vcxproj @@ -255,10 +255,6 @@ {bc2e9ea5-ebc4-4fdf-b064-e2bbbbcba1d3} false - - {17cf5e05-f29c-4e5d-ba41-83254e342e0b} - false - From a2a7a0ef4cb7faf25c870d854c818424307fa664 Mon Sep 17 00:00:00 2001 From: Maciej Zagozda Date: Fri, 27 Mar 2026 18:49:38 +0100 Subject: [PATCH 6/6] Improved installer process --- src/plugins/pictview/vcxproj/salpvenv.vcxproj | 101 ------------------ .../pictview/vcxproj/salpvenv_base.props | 32 ------ .../pictview/vcxproj/salpvenv_debug.props | 24 ----- .../pictview/vcxproj/salpvenv_release.props | 31 ------ 4 files changed, 188 deletions(-) delete mode 100644 src/plugins/pictview/vcxproj/salpvenv.vcxproj delete mode 100644 src/plugins/pictview/vcxproj/salpvenv_base.props delete mode 100644 src/plugins/pictview/vcxproj/salpvenv_debug.props delete mode 100644 src/plugins/pictview/vcxproj/salpvenv_release.props diff --git a/src/plugins/pictview/vcxproj/salpvenv.vcxproj b/src/plugins/pictview/vcxproj/salpvenv.vcxproj deleted file mode 100644 index c83a3719..00000000 --- a/src/plugins/pictview/vcxproj/salpvenv.vcxproj +++ /dev/null @@ -1,101 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - 16.0 - {17CF5E05-F29C-4E5D-BA41-83254E342E0B} - salpvenv - 10.0 - - - - - false - v143 - Application - - - true - v143 - Application - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - stdcpplatest - - - - - stdcpplatest - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/plugins/pictview/vcxproj/salpvenv_base.props b/src/plugins/pictview/vcxproj/salpvenv_base.props deleted file mode 100644 index 83c710bd..00000000 --- a/src/plugins/pictview/vcxproj/salpvenv_base.props +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - $(OPENSAL_BUILD_DIR)salamander\$(Configuration)_x64\plugins\pictview\ - $(OutDir)Intermediate\SalPVEnv_x86\ - false - false - - - - ..\..\shared;%(AdditionalIncludeDirectories) - WIN32;WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_IE=0x0800;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;BUILD_ENVELOPE;%(PreprocessorDefinitions) - false - Level3 - - - false - - - false - true - Windows - - - WINVER=0x0601;%(PreprocessorDefinitions) - 0x0409 - - - diff --git a/src/plugins/pictview/vcxproj/salpvenv_debug.props b/src/plugins/pictview/vcxproj/salpvenv_debug.props deleted file mode 100644 index 8ad74617..00000000 --- a/src/plugins/pictview/vcxproj/salpvenv_debug.props +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - true - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebug - - - false - ..\..\shared\baseaddr_$(ShortPlatform).txt,$(ProjectName) - - - _DEBUG;%(PreprocessorDefinitions) - - - \ No newline at end of file diff --git a/src/plugins/pictview/vcxproj/salpvenv_release.props b/src/plugins/pictview/vcxproj/salpvenv_release.props deleted file mode 100644 index e5401747..00000000 --- a/src/plugins/pictview/vcxproj/salpvenv_release.props +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - false - - - - MaxSpeed - true - NDEBUG;%(PreprocessorDefinitions) - true - MultiThreaded - true - - - true - true - true - UseLinkTimeCodeGeneration - - - NDEBUG;%(PreprocessorDefinitions) - - - call ..\..\..\..\tools\codesign\sign_with_retry.cmd "$(TargetPath)" - - -