Files
2026-04-17 14:55:32 -04:00

7.1 KiB

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
DataPRO/Modules/InstallerCustomActions/Common/PreviousInstall.cs
2026-04-16T04:43:42.723638+00:00 Qwen/Qwen3-Coder-Next-FP8 1 d9773bfec96b878e

Common

Purpose

This module provides utilities for detecting and retrieving information about previously installed versions of the DataPRO application during Windows Installer custom actions. Specifically, it locates the most recent lower version of DataPRO installed on the system (i.e., older than the version being installed) by querying the Windows Registry under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall (and fallback to Components), enabling upgrade or migration logic in the installer. It is intended for use in Windows Installer custom actions to support version-aware installation scenarios.


Public Interface

static string GetMostRecentlyInstalledSubKeyName(Version installingVersion, out string mostRecentlyInstalledLowerVersion)

  • Behavior: Scans the registry under the Uninstall key (path defined by Settings.Default.RegistrySoftwareInstalledProducts) for installed products whose display name matches Settings.Default.RegistryDataPRO. Among those with a version strictly less than installingVersion, it returns the registry subkey name (ProductCode or similar identifier) of the most recent (i.e., highest) version.
  • Output parameter mostRecentlyInstalledLowerVersion: Contains the string representation (e.g., "1.2.3.4") of the highest version found that is less than installingVersion, or string.Empty if none found.
  • Returns: The registry subkey name (e.g., "DataPRO-abc123") of the most recent lower version, or string.Empty if no matching product is found or registry access fails.

static string GetMostRecentlyInstalledPath(string mostRecentlyInstalledSubKeyName)

  • Behavior: Given a registry subkey name (typically obtained from GetMostRecentlyInstalledSubKeyName), this method attempts to resolve the installation path (InstallLocation) of that product.
  • Logic:
    1. First searches in RegistrySoftwareInstalledProducts (Uninstall), looking for the matching subkey and retrieving InstallLocation (Settings.Default.RegistryInstallLocation).
    2. If not found, falls back to searching in RegistrySoftwareInstalledComponents, where the value named mostRecentlyInstalledSubKeyName is expected to hold a full path ending with Settings.Default.RegistryDataPROExeConfig (e.g., "DataPRO.exe.config"), from which the directory is extracted.
    3. Appends Settings.Default.RegistryDataPRO + "\\" to the path if the path contains Settings.Default.DTSSuite, to ensure correct nesting (e.g., for suite-based installations).
  • Returns: The resolved installation directory path (e.g., "C:\Program Files\DTSSuite\DataPRO\\"), or string.Empty if not found or invalid.

static bool IsGreaterThan(this Version leftString, Version rightString)

  • Behavior: Extension method for System.Version. Returns true if leftString is greater than rightString (i.e., leftString.CompareTo(rightString) > 0).

static bool IsLessThan(this Version leftString, Version rightString)

  • Behavior: Extension method for System.Version. Returns true if leftString is less than rightString (i.e., leftString.CompareTo(rightString) < 0).

Invariants

  • Only products with DisplayName equal to Settings.Default.RegistryDataPRO are considered.
  • Only versions strictly less than the installingVersion are considered in GetMostRecentlyInstalledSubKeyName.
  • The method GetMostRecentlyInstalledSubKeyName returns the highest version among qualifying products (not the most recently installed chronologically, but the highest version number).
  • Registry access is performed exclusively on RegistryHive.LocalMachine with RegistryView.Registry64.
  • Paths retrieved via GetMostRecentlyInstalledPath are normalized by stripping the trailing Settings.Default.RegistryDataPROExeConfig (e.g., "DataPRO.exe.config") when sourced from the Components key.
  • If a registry value is missing or evaluates to "-1" (as a string), it is treated as invalid and skipped.

Dependencies

  • External:
    • Microsoft.Win32.RegistryKey (for registry access).
    • System.Version (for version comparison).
    • System.Diagnostics.EventLog (used internally for logging in GetMostRecentlyInstalledPath).
  • Internal:
    • Common.Properties.Settings.Default:
      • RegistrySoftwareInstalledProducts (e.g., "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall").
      • RegistrySoftwareInstalledComponents (e.g., "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Installation\\Components").
      • RegistryInstallProperties (e.g., "InstallProperties" subkey).
      • RegistryDisplayName (e.g., "DisplayName").
      • RegistryDisplayVersion (e.g., "DisplayVersion").
      • RegistryInstallLocation (e.g., "InstallLocation").
      • RegistryDataPRO (e.g., "DataPRO").
      • RegistryDataPROExeConfig (e.g., "DataPRO.exe.config").
      • DTSSuite (e.g., "DTSSuite").
  • Used by: Windows Installer custom actions (not visible in source, but implied by namespace Installer.Common and method naming).

Gotchas

  • Hardcoded fallback to "-1": Registry values are read with RegistryValueOptions.None, and if the result is "-1" (string), it is treated as invalid. This assumes "-1" is used as a sentinel for missing/invalid values—a convention not guaranteed by Windows Installer or .NET.
  • No error handling for registry access: If OpenSubKey or GetValue throws (e.g., due to permissions or corruption), the exception propagates unhandled. Logging in GetMostRecentlyInstalledPath uses EventLog, but only for informational paths, not errors.
  • Assumes 64-bit registry view only: Uses RegistryView.Registry64, which may miss 32-bit installations on 64-bit systems (though HKEY_LOCAL_MACHINE\SOFTWARE redirection would apply).
  • Ambiguity in mostRecentlyInstalledSubKeyName: The term "most recently installed" in the method name is misleading—it actually returns the highest version, not the one with the latest install timestamp.
  • Path normalization quirk: The suffix stripping in GetMostRecentlyInstalledPath assumes mostRecentlyInstalledSubKeyName ends exactly with RegistryDataPROExeConfig. If the value is malformed or truncated, substring logic may yield incorrect paths.
  • No fallback for missing InstallLocation: If InstallLocation is absent in Uninstall, and the Components lookup fails or yields an invalid path, the method returns string.Empty without indicating why.
  • Event log source must exist: log.Source = "DataPROInstaller" assumes the event source is pre-registered; otherwise, WriteEntry may throw on first use (though this is rare in installer contexts).
  • No handling for Version parsing failures: If RegistryDisplayVersion contains a non-parsable string (e.g., "1.2.3-beta"), new Version(strThisVersion) throws FormatException.