--- 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 Installer’s 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.*