This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
---
source_files:
- DataPRO/Modules/InstallerCustomActions/RegAddProductCode/AddProductCode.cs
generated_at: "2026-04-16T04:43:28.721583+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "c22465a70e9ccf40"
---
# RegAddProductCode
## Documentation: `AddProductCode.cs` — Installer Custom Action for Registry Policy Configuration
---
### 1. Purpose
This module implements a Windows Installer custom action (`AddProductCode`) responsible for configuring Windows Installer security policies in the registry prior to or during DataPRO installation. Specifically, it enforces the `SecureRepairPolicy` setting and adds the DataPRO product code to the `SecureRepairWhitelist`, enabling the installer to perform repair operations on `DataPRO.exe` and its dependencies without being blocked by Windows Installers secure repair restrictions. It also validates architecture compatibility between the installer process (32- or 64-bit) and the operating system, terminating the installation with a user-facing error if a mismatch is detected (e.g., 32-bit installer on 64-bit OS), to prevent downstream failures such as incompatible SQL LocalDB version conflicts.
---
### 2. Public Interface
The class `AddProductCode` exposes only one public entry point:
#### `static int Main(string[] args)`
- **Signature**: `private static int Main(string[] args)`
- **Behavior**:
Entry point for the custom action. Parses `args[0]` as `architectureVersion` (`"x86"` or `"x64"`), logs environment details (process bitness, OS bitness), and performs architecture validation:
- If `architectureVersion == "x86"` and OS is 64-bit → shows error message and returns `1`.
- If `architectureVersion == "x64"` and OS is 32-bit → shows error message and returns `1`.
- Otherwise, calls `AddCodeToRegistry()` and returns `0` (success) or `1` (failure if registry write fails).
- Logging is performed via `EventLog.WriteEntry` under source `"DataPROInstaller"`.
> **Note**: Though declared `private`, this method is the *de facto* public entry point for the custom action as invoked by the Windows Installer (e.g., via `CustomAction` table). It is not called internally.
---
### 3. Invariants
- **Architecture Consistency**:
The installer process bitness must match the target OS bitness *relative to the requested architecture* (`args[0]`). Mismatches cause early termination with exit code `1`.
- **Registry Hive & View**:
All registry modifications target `HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer` using `RegistryView.Registry64`, ensuring writes occur in the 64-bit view even on 64-bit systems (i.e., not redirected to `WOW6432Node`).
- **Policy Values**:
The following must be set:
- `SecureRepairPolicy` (DWORD) = `2` (enables secure repair for whitelisted products).
- `SecureRepairWhitelist\{C4889149-0CAF-44C1-B226-8F6E73684DF4}` (DWORD) = `0` (adds product code to whitelist).
- **Exit Codes**:
- `0`: Success (registry updated or already correct).
- `1`: Failure due to architecture mismatch or registry write error.
---
### 4. Dependencies
#### Imports / External Dependencies:
- `System.Diagnostics.EventLog` for installer logging.
- `Microsoft.Win32.RegistryKey`, `RegistryHive`, `RegistryView`, `RegistryValueKind` for registry access.
- `System.Windows.Forms.MessageBox` for user-facing error messages.
- `RegAddProductCode.Properties.Settings.Default` static configuration values:
- `Settings.Default.InstallerKey`: Registry path `"SOFTWARE\\Policies\\Microsoft\\Windows\\Installer"`
- `Settings.Default.SecureRepairPolicy`: Policy value name `"SecureRepairPolicy"`
- `Settings.Default.SecureRepairWhitelistKey`: Subkey path `"SOFTWARE\\Policies\\Microsoft\\Windows\\Installer\\SecureRepairWhitelist"`
- `Settings.Default.ProductCode`: Product code GUID `"{C4889149-0CAF-44C1-B226-8F6E73684DF4}"`
- `Settings.Default.MissingKey`: Format string for error messages (e.g., `"Registry key missing: {0}"`).
#### Usage:
- **Called by**: Windows Installer as a custom action (likely in a WiX or similar MSI project).
- **Depends on**:
- Administrative privileges (required to write to `HKLM\SOFTWARE\Policies\...`).
- `EventLog` source `"DataPROInstaller"` must exist or be creatable by the installer process.
---
### 5. Gotchas
- **Hardcoded Product Code**:
The product code `"{C4889149-0CAF-44C1-B226-8F6E73684DF4}"` is hardcoded in both `Settings.Default.ProductCode` and the whitelist logic. Changing the product code in the installer project requires updating this value manually—no dynamic injection is present.
- **Silent Failure Risk in 32-bit on 64-bit**:
The comment explains that allowing a 32-bit installer on 64-bit OS could cause the SQL LocalDB 2014 prerequisite to fail silently, leading to runtime DB version incompatibility. This is a *preventive guard*, but the fix is architectural (blocking 32-bit installers entirely on 64-bit OS), not a workaround.
- **Registry View Hardcoded to 64-bit**:
`RegistryView.Registry64` is used unconditionally—even on 32-bit OSes. While `OpenBaseKey` with `Registry64` on a 32-bit OS is safe (it falls back to the native view), this may be unintentional or legacy. No explicit fallback to `RegistryView.Registry32` exists.
- **No Rollback Handling**:
If `AddCodeToRegistry()` succeeds but the main installer fails later, the registry changes are *not* rolled back. The policy settings remain in place.
- **Commented-Out UI Error**:
The line `// MessageBox.Show(result);` is commented out in `Main()`, meaning registry errors are *only* logged to Event Log, not shown to the user. This may reduce visibility during silent installs.
- **No Exception Handling Granularity**:
`AddCodeToRegistry()` catches all exceptions generically and returns only the message string. Specific exceptions (e.g., `UnauthorizedAccessException`, `SecurityException`) are not differentiated.
- **Assumes Installer Runs with Admin Rights**:
The code assumes the custom action runs with elevated privileges. If not, registry writes will fail silently (or with generic error), and no fallback is implemented.
---
*End of documentation.*