init
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/Common/PreviousInstall.cs
|
||||
generated_at: "2026-04-16T04:43:42.723638+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "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`.
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/Common/Properties/AssemblyInfo.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/Common/Properties/Settings.Designer.cs
|
||||
generated_at: "2026-04-16T04:44:41.257169+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "3a215b4dad8b4fc8"
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
## Documentation Page: `Installer.Common` Module
|
||||
|
||||
---
|
||||
|
||||
### 1. **Purpose**
|
||||
|
||||
This module (`Installer.Common`) is a shared .NET assembly containing configuration and metadata constants used across custom actions in the DataPRO Windows Installer infrastructure. Its primary role is to centralize registry path keys, value names, and application identifiers used during installation, upgrade, and uninstallation logic—specifically for querying and interacting with Windows Installer (MSI) metadata stored in the registry. It does *not* contain executable installer logic itself but provides stable, versioned configuration values to ensure consistency across installer components.
|
||||
|
||||
---
|
||||
|
||||
### 2. **Public Interface**
|
||||
|
||||
The module exposes **no public types** (classes, methods, or properties) beyond the auto-generated settings class `Common.Properties.Settings`. All other types are internal to the assembly (e.g., `AssemblyInfo` attributes are compile-time metadata, not runtime API surface).
|
||||
|
||||
#### `Common.Properties.Settings`
|
||||
|
||||
- **Type**: `internal sealed partial class Settings : ApplicationSettingsBase`
|
||||
- **Access**: Public static property `Settings.Default` (read-only)
|
||||
- **Behavior**: Provides application-scoped configuration values for registry paths and display names used during MSI operations.
|
||||
|
||||
##### Public Properties (read-only, application-scoped):
|
||||
|
||||
| Property Name | Type | Default Value | Description |
|
||||
|---------------|------|---------------|-------------|
|
||||
| `RegistrySoftwareInstalledProducts` | `string` | `"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Products"` | Registry path where MSI stores installed product data (per-user SID `S-1-5-18` = LocalSystem context). |
|
||||
| `RegistryInstallProperties` | `string` | `"InstallProperties"` | Subkey name under a product path where install metadata resides. |
|
||||
| `RegistryDisplayName` | `string` | `"DisplayName"` | Registry value name for the user-facing product name. |
|
||||
| `RegistryDataPRO` | `string` | `"DataPRO"` | Subkey name used to identify DataPRO-specific registry entries (e.g., under `InstallProperties`). |
|
||||
| `RegistryDisplayVersion` | `string` | `"DisplayVersion"` | Registry value name for the installed version string. |
|
||||
| `RegistrySoftwareInstalledComponents` | `string` | `"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Components"` | Registry path where MSI stores component-to-product mapping. |
|
||||
| `RegistryDataPROExeConfig` | `string` | `"DataPRO.exe.config"` | Registry value name (likely under install location) referencing the app config file. |
|
||||
| `RegistryInstallLocation` | `string` | `"InstallLocation"` | Registry value name for the installation directory path. |
|
||||
| `DTSSuite` | `string` | `"DTS.Suite"` | Identifier for the DTS suite (possibly used for feature grouping or upgrade detection). |
|
||||
|
||||
> **Note**: All properties are `ApplicationScopedSettingAttribute`, meaning their values are fixed at compile time and cannot be modified at runtime.
|
||||
|
||||
---
|
||||
|
||||
### 3. **Invariants**
|
||||
|
||||
- The registry paths use the **LocalSystem SID (`S-1-5-18`)** explicitly, implying these settings are intended for use in contexts where the installer runs with elevated (system) privileges (e.g., custom actions executing as `System`).
|
||||
- Registry paths and value names are **hardcoded strings**—no dynamic resolution or runtime computation occurs.
|
||||
- The `Settings.Default` instance is **thread-safe** (via `ApplicationSettingsBase.Synchronized`), but only for reading values; no write operations are supported (all settings are `ApplicationScoped`).
|
||||
- The `RegistryDataPRO` value (`"DataPRO"`) is used as a *key* or *subkey name*, not a value—suggesting it may be part of a hierarchy like:
|
||||
`...\Products\<ProductCode>\InstallProperties\DataPRO\...`
|
||||
- Version information is **not exposed** via this module (assembly version is `1.0.0.0` but not used in logic).
|
||||
|
||||
---
|
||||
|
||||
### 4. **Dependencies**
|
||||
|
||||
#### Dependencies *of* this module:
|
||||
- `System.Configuration` (for `ApplicationSettingsBase`, `ApplicationScopedSettingAttribute`, etc.)
|
||||
- `System.Runtime.CompilerServices`, `System.CodeDom.Compiler`, `System.Diagnostics` (for attributes only)
|
||||
|
||||
#### Dependencies *on* this module:
|
||||
- **Inferred consumers**: Other modules in `DataPRO/Modules/InstallerCustomActions/` (e.g., custom action DLLs) that need to read MSI registry metadata.
|
||||
Example usage pattern (not in source, but implied):
|
||||
```csharp
|
||||
string productsPath = Common.Properties.Settings.Default.RegistrySoftwareInstalledProducts;
|
||||
```
|
||||
- Likely used in conjunction with Windows Installer APIs (e.g., `MsiEnumProducts`, `MsiGetProductInfo`) or direct registry access (`Microsoft.Win32.Registry`).
|
||||
|
||||
---
|
||||
|
||||
### 5. **Gotchas**
|
||||
|
||||
- **Hardcoded SID**: The use of `S-1-5-18` (LocalSystem) may break if installer logic runs under a different context (e.g., per-user install with non-elevated user). No fallback or SID resolution is present.
|
||||
- **No versioning in settings**: The `AssemblyVersion` is `1.0.0.0` but the settings themselves are not versioned—changing a registry path here could silently break existing upgrade logic if not coordinated with installer versioning.
|
||||
- **Auto-generated file warning**: `Settings.Designer.cs` explicitly warns that manual changes will be lost on regeneration (e.g., via Visual Studio designer). This implies the settings are managed in a `.settings` designer file (not visible here).
|
||||
- **No null-safety**: Property getters return the raw registry value—no validation or defaulting is done. If a registry value is missing, callers must handle `null`.
|
||||
- **Ambiguous `DTSSuite` usage**: The purpose of `"DTS.Suite"` is unclear from this module alone—it may be used as a feature ID, upgrade code prefix, or registry grouping key, but no evidence of its usage exists in the provided files.
|
||||
|
||||
> **None identified from source alone.** (Applied only if no issues found—here, several are inferred from structure and naming.)
|
||||
|
||||
---
|
||||
|
||||
**End of Documentation**
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/DBConfiguration/MigrationStatus.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/DBConfiguration/DBConfig.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/DBConfiguration/CommonUtilities.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/DBConfiguration/DBTypeChoice.Designer.cs
|
||||
generated_at: "2026-04-16T04:44:09.733583+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "34f445ff6d14ccf5"
|
||||
---
|
||||
|
||||
# Documentation: DBConfiguration Module
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module provides database configuration and initialization logic for the DataPRO application during installation and migration scenarios. It serves as a standalone executable (`DBConfiguration.exe`) that handles local SQL Server Express LocalDB instance management—including creation, attachment, and detachment of databases (`DataPRO` and `ISO`)—and supports multiple initialization modes (e.g., TSR AIR, Crash, Aero, migration from previous local DB). It also exposes a minimal `MigrationStatus` class for conveying progress during operations. The module is invoked by the installer (via command-line arguments) or standalone (for debugging/testing), and integrates with Windows Forms for interactive configuration when UI is enabled.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `DBConfiguration.MigrationStatus`
|
||||
- **`StatusTypes` enum**: Defines three status categories: `Status`, `MigrationStatus`, and `SourceDb`.
|
||||
- **`StatusType` property (`StatusTypes`)**: Indicates the type of status being reported.
|
||||
- **`StatusText` property (`string`)**: Contains the human-readable status message.
|
||||
|
||||
### `DBConfiguration.DBConfig`
|
||||
- **`Main(string[] args)`**: Static entry point. Parses command-line arguments to determine execution mode (installer vs. standalone, UI vs. silent), and dispatches to either `DBTypeChoice` form (interactive) or `CommonUtilities.InitializeDbToTSRAIR()` (TSR AIR initialization). In installer mode, it hides the console window; in standalone command mode, it shows it.
|
||||
|
||||
### `DBConfiguration.CommonUtilities`
|
||||
- **`InitializeDbToTSRAIR(string targetDir)`**: Initializes the database to TSR AIR settings. Performs the following sequence:
|
||||
1. Calls `ConfigInitializationHelper.UpdateTSRAIRAppSettings(targetDir, true)` (not shown in source; assumed external).
|
||||
2. Calls `Attach(targetDbDir, scriptsDir)` to attach existing databases.
|
||||
3. Calls `DbOperations.Connection.Initialize(InitializationTypes.TSRAIR, targetDir)` (assumed external).
|
||||
4. Calls `Detach(...)` to detach the migrated databases.
|
||||
5. Shows a success message box.
|
||||
- **`Attach(string targetDbDir, string scriptsDir)`**: Logs and sets migration status, then calls `InstallDatabase(targetDbDir, "DataPRO", scriptsDir)`.
|
||||
- **`InstallDatabase(string dBdir, string dbName, string scriptsDir)`**: Performs full LocalDB instance setup:
|
||||
- Sets connection properties (`Server = Settings.Default.LocalDbDataPROInstance`, `NTLMAuthentication = true`, `usingCentralizedDB = false`, `usingMSSQL = true`).
|
||||
- Executes SQL LocalDB commands via `ProcessSqlLocalDbCommand(...)` to stop, delete, create, and start the LocalDB instance.
|
||||
- Attaches `DataPRO.mdf` and `ISO.mdf` databases using `AttachOrDetachDatabase(...)` with `Settings.Default.AttachDBsbat`.
|
||||
- Returns any error output from SQL commands.
|
||||
- **`Detach(string sourceDbName, string targetDbDir, string scriptsDir)`**: Detaches the `sourceDbName` (typically `"DataPRO"`) and `ISO` databases using `AttachOrDetachDatabase(...)` with `Settings.Default.DetachDBsbat`. Logs status and shows warnings if errors occur.
|
||||
- **`SetMigrationStatus(string migrationStatus, bool output = false)`**: Creates and returns a `MigrationStatus` object with `StatusType = StatusTypes.MigrationStatus` and the given `migrationStatus` text. Optionally writes to `Console.WriteLine`.
|
||||
- **`ProcessSqlLocalDbCommand(string command)`**: Executes a command (e.g., `"start v14.0"`, `"create v14.0"`) against SQL Server LocalDB by:
|
||||
- Resolving the LocalDB installation path via `GetSqlServerLocalDBPath()`.
|
||||
- Invoking `sqllocaldb.exe` via `SqlCommandProcessor(...)`.
|
||||
- Returns non-empty string on error (e.g., `"localdb not installed"`).
|
||||
- **`GetSqlServerLocalDBPath()`**: Queries the registry (`HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\LocalDB\Installed Versions`) to find the highest installed LocalDB version with a valid `SqlUserInstance.dll` path. Returns the path to the `Tools` directory (e.g., `C:\Program Files\Microsoft SQL Server\140\Tools\`).
|
||||
- **`AttachOrDetachDatabase(string scriptsDir, string dbName, string sqlDbFileName, string sqlLogFileName, string attachOrDetach)`**: Invokes a batch script (e.g., `AttachDBs.bat`) via `BatchCommandProcessor(...)`. The batch script is expected to use `sqlcmd.exe` to execute `CREATE DATABASE ... FOR ATTACH`.
|
||||
- **`SqlCommandProcessor(string sqlLocalDbExeFileName, string command)`**: Executes a command-line process (`sqllocaldb.exe`) asynchronously, capturing output via `OutputHandler`. Returns captured output if non-empty.
|
||||
- **`BatchCommandProcessor(string batchFileName, string dbName, string sqlDbFileName, string sqlLogFileName, string fullSqlcmdPath)`**: Executes a batch file with arguments: `dbName`, quoted `dbFileName`, quoted `logFileName`, and quoted `sqlcmd.exe` path. Uses same async output capture mechanism.
|
||||
|
||||
> **Note**: `SetStatus(string status, bool output = false)` is private and used internally; not part of the public interface.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **LocalDB instance name**: Hardcoded to `"DataPRO"` in `InstallDatabase` and `Attach`. Cannot be changed during TSR AIR Go installation.
|
||||
- **Database files**: Always expects `DataPRO.mdf`/`DataPRO.ldf` and `ISO.mdf`/`ISO.ldf` in `targetDbDir`.
|
||||
- **Authentication**: Uses NTLM authentication (`DbOperations._usingNTLMAuthentication = true`) for all LocalDB operations.
|
||||
- **Centralized DB flag**: `DbOperations._usingCentralizedDB` is explicitly set to `false` during LocalDB operations.
|
||||
- **Console visibility**: In installer mode (`args.Length > 0` and `noUI != "STANDALONECMD"`), the console window is hidden (`SW_HIDE`). In standalone command mode (`args.Length == 2`), it is shown (`SW_SHOW`).
|
||||
- **TSR AIR mode**: When `tsrAirGo == true`, the UI (`DBTypeChoice`) is skipped entirely.
|
||||
- **Registry query**: Only queries 64-bit registry view (`RegistryView.Registry64`).
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### External Dependencies (from imports/includes):
|
||||
- `System`, `System.Windows.Forms`, `System.Diagnostics`, `System.IO`, `System.Text`, `Microsoft.Win32`
|
||||
- `DTS.Common.Storage`, `DTS.Common.Enums`, `DTS.Common.Utilities`, `DTS.Common.Utils.Database`
|
||||
- `DBConfiguration.Properties` (for `Settings.Default`)
|
||||
|
||||
### Internal Dependencies:
|
||||
- `DBTypeChoice` (Windows Form class, defined in `DBTypeChoice.Designer.cs` and implied `DBTypeChoice.cs` not provided).
|
||||
- `DbOperations` (static class with `Connection` and `_usingCentralizedDB`, `_usingMSSQL`, `_usingNTLMAuthentication` fields; not shown but referenced).
|
||||
- `ConfigInitializationHelper` (static class with `UpdateTSRAIRAppSettings(...)` method; not shown).
|
||||
- `Settings.Default`: Used extensively for strings (e.g., `LocalDbFolder`, `ScriptsFolder`, `LocalDbDataPROInstance`, `Mdf`, `LogLdf`, `AttachDBsbat`, `DetachDBsbat`, `StopDataProInstance`, `DeleteDataProInstance`, `CreateDataProInstance`, `StartDataProInstance`, `ISO`, `SqlServerLocalDbNotInstalled`, `Warning`, `InstallationStatus`, `TSRAIRGoInstallationCompletedSuccessfully`, `AttachingPrevLocalDb`, `DetachingLocalMigratedDb`, `DetachingLocalISODb`, `AttachDBsbat`, `DetachDBsbat`, `RegistrySoftwareMicrosoftMicrosoftSQLServerLocalDBInstalledVersions`, `InstanceAPIPath`, `SqlUserInstanceDll`, `LocalDB`, `Tools`, `SqlLocalDBExe`).
|
||||
|
||||
### Dependencies on this module:
|
||||
- The installer (likely WiX or similar) invokes `DBConfig.Main(...)` with specific command-line arguments during installation.
|
||||
- Other modules may rely on `CommonUtilities` for database setup logic (though only `InitializeDbToTSRAIR` is called from `DBConfig`).
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Hardcoded database name**: `"DataPRO"` is hardcoded in `InstallDatabase` and `Attach`. Changing this requires updating multiple locations.
|
||||
- **Registry path assumptions**: `GetSqlServerLocalDBPath()` assumes a specific registry path (`...\LocalDB\Installed Versions`) and that subkeys are version numbers (e.g., `"11.0"`, `"14.0"`). Failure to parse a subkey as a double silently skips it.
|
||||
- **`SqlUserInstanceDll` check**: Only considers versions where the `InstanceAPIPath` value ends with `"SqlUserInstance.dll"`. If the path format changes, LocalDB resolution fails.
|
||||
- **Console window toggling**: The console window is hidden/shown based on `args.Length` and `noUI` value. Misunderstanding the argument semantics may lead to unexpected UI behavior (e.g., window flashing).
|
||||
- **`tsrAirGo` override**: When `tsrAirGo == true`, the entire `DBTypeChoice` form is skipped—even if `noUI != "TRUE"`. This may conflict with expectations if `noUI` is `"TRUE"` but `tsrAirGo` is also set.
|
||||
- **Error handling**: Errors from SQL commands are returned as strings and displayed via `MessageBox.Show(...)`, but the method continues execution (e.g., `InstallDatabase` proceeds even if `ProcessSqlLocalDbCommand` returns non-empty). This may leave the system in a partially configured state.
|
||||
- **`sb` static field**: `CommonUtilities.sb` is a static `StringBuilder` used for output capture. Concurrent calls to `SqlCommandProcessor` or `BatchCommandProcessor` (if ever introduced) would interfere with each other.
|
||||
- **Missing implementation details**: Key dependencies like `DbOperations.Connection.Initialize(...)`, `ConfigInitializationHelper.UpdateTSRAIRAppSettings(...)`, and `Settings.Default` values are referenced but not defined in the provided source. Their behavior is inferred but not verifiable here.
|
||||
- **No rollback logic**: If `Attach` succeeds but `Detach` fails, there is no cleanup or error recovery—databases remain attached until manually detached.
|
||||
- **`ProcessSqlLocalDbCommand` return value**: Returns non-empty string on error, but callers treat *any* non-empty string as a warning (via `MessageBox.Show`) and continue. This may mask critical failures.
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/DBConfiguration/Properties/AssemblyInfo.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/DBConfiguration/Properties/Resources.Designer.cs
|
||||
generated_at: "2026-04-16T04:44:51.764845+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "f9b9065d14e86b8a"
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
## Documentation: `DBConfiguration` Assembly
|
||||
|
||||
### 1. Purpose
|
||||
This module is a .NET assembly named **DBConfiguration**, part of the `DataPRO/Modules/InstallerCustomActions` component hierarchy. Its role is to support database-related configuration tasks during Windows Installer custom actions—though the provided source files contain only metadata and auto-generated resource infrastructure, not the actual implementation logic. As such, this assembly serves as a placeholder or container for installer-time database setup operations (e.g., schema creation, connection string validation, or service account configuration), with the actual behavior residing in other modules or files not included here.
|
||||
|
||||
### 2. Public Interface
|
||||
**No public API surface is exposed by this assembly.**
|
||||
- The `AssemblyInfo.cs` file defines assembly-level attributes (e.g., `AssemblyTitle`, `AssemblyVersion`) but no types or methods.
|
||||
- The `Resources.Designer.cs` file defines an internal, auto-generated class `DBConfiguration.Properties.Resources`. This class is **not public** (`internal class Resources`) and provides only strongly-typed resource accessors (`ResourceManager`, `Culture`) for localized strings. It does not expose any functional APIs beyond resource lookup infrastructure.
|
||||
|
||||
> ⚠️ **Note**: The actual installer custom action classes (e.g., classes inheriting from `System.Configuration.Install.Installer`) or database configuration logic are not present in the provided files and must be located elsewhere in the codebase.
|
||||
|
||||
### 3. Invariants
|
||||
- The assembly is **not COM-visible** (`[assembly: ComVisible(false)]`), meaning its types cannot be accessed via COM interop unless explicitly exposed through other means (e.g., public classes with `[ComVisible(true)]`, which are absent here).
|
||||
- The assembly version is fixed at `1.0.0.0` for both `AssemblyVersion` and `AssemblyFileVersion`.
|
||||
- The `Resources` class is auto-generated and must be regenerated if the underlying `.resx` file changes (per the header comment in `Resources.Designer.cs`). Manual edits to `Resources.Designer.cs` will be overwritten.
|
||||
- The `Guid` attribute (`a5087f45-0949-4e27-b367-ccb6556fc68d`) uniquely identifies this assembly’s type library for COM registration purposes, though COM visibility is disabled.
|
||||
|
||||
### 4. Dependencies
|
||||
- **Runtime dependencies**:
|
||||
- `System.dll` (implicit, via `System.Reflection`, `System.Runtime.InteropServices`, `System.Resources`, `System.Globalization`).
|
||||
- `System.Core.dll` (likely, for `System.CodeDom.Compiler`, `System.ComponentModel`, `System.Diagnostics`).
|
||||
- **Internal dependencies**:
|
||||
- This assembly likely depends on other modules in `DataPRO/Modules/InstallerCustomActions` (e.g., shared installer utilities or database access libraries), but no explicit references are declared in the provided files.
|
||||
- **Consumers**:
|
||||
- Presumably consumed by the Windows Installer (via custom action DLL registration) or by the `DataPRO` setup project.
|
||||
- May be referenced by other `DataPRO` modules requiring database configuration during installation.
|
||||
|
||||
### 5. Gotchas
|
||||
- **No functional code in provided files**: The assembly’s purpose is inferred from naming and directory structure, but the actual database configuration logic is absent. Developers should not expect to find custom action entry points (e.g., `Install`, `Commit`, `Rollback`) here.
|
||||
- **Resource class is internal**: While `Resources` provides localized string support, it is `internal`, meaning external consumers (e.g., other assemblies) cannot directly access it. Localization is likely used only within this assembly’s implementation (which is not visible here).
|
||||
- **Versioning rigidity**: The `AssemblyVersion` is hardcoded to `1.0.0.0` with no wildcard (`*`), meaning build/revision numbers cannot auto-increment. This may complicate deployment tracking if not managed externally.
|
||||
- **Auto-generated code warning**: `Resources.Designer.cs` explicitly warns that manual changes will be lost on regeneration. Any localization adjustments must be made in the corresponding `.resx` file.
|
||||
- **None identified from source alone.**
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/LocalSQLDB/LocalDBPreparation.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/LocalSQLDB/LocalDBPrepare.cs
|
||||
generated_at: "2026-04-16T04:44:18.702457+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "53877159cb79be1f"
|
||||
---
|
||||
|
||||
# LocalDB Preparation Module Documentation
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This module implements a Windows Installer custom action responsible for preparing a local SQL Server Express LocalDB instance during installation of the DataPRO application. Specifically, it determines whether the installation targets a *local* or *centralized* database configuration, and if local, copies the default database files (`DataPRO.mdf` and `DataPRO.ldf`) from a previously installed version (if available) or from the current installation directory to a new location named according to the configured database name. It ensures the database files are present before the main installation completes, enabling the application to connect to a pre-populated local database.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### `LocalDBPreparation.Main(string[] args)`
|
||||
- **Signature**: `static void Main(string[] args)`
|
||||
- **Behavior**: Entry point for the custom action executable. Parses the first two arguments as `targetDir` (installation directory) and `productVersion` (version of the product being installed). Instantiates `LocalDBPrepare` with these values and invokes `PrepareDB()`. On any exception, displays an error message via `MessageBox.Show` and rethrows an exception to abort the installation.
|
||||
|
||||
### `LocalDBPrepare.PrepareDB()`
|
||||
- **Signature**: `public bool PrepareDB()`
|
||||
- **Behavior**: Orchestrates the database preparation logic:
|
||||
1. Reads the new installation’s configuration file to determine the database type (`DBType`) and database name (`DBName`).
|
||||
2. If `DBType` is `Centralized`, returns `false` immediately (no local DB preparation needed).
|
||||
3. If the configured `DBName` matches the default (`Settings.Default.DataPRO`), returns `true` without copying (no rename needed).
|
||||
4. Otherwise, constructs source and destination paths for `.mdf` and `.ldf` files.
|
||||
5. Attempts to locate the most recently installed lower version using `Common.PreviousInstall.GetMostRecentlyInstalledSubKeyName` and `GetMostRecentlyInstalledPath`. If no prior version is found, returns `false`.
|
||||
6. Copies `DataPRO.mdf` and `DataPRO.ldf` from the source path to the destination path (overwriting existing files).
|
||||
7. Returns `true` upon successful copy.
|
||||
|
||||
> **Note**: The method is *not* thread-safe, as it uses static fields (`_targetDir`, `_installingVersion`) to store state.
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
- **Configuration File Path**: The configuration file is expected at `<targetDir><RegistryDataPROExe>` (e.g., `targetDir + "DataPRO.exe"`), where `RegistryDataPROExe` is a string constant from `Settings.Default`.
|
||||
- **Database File Naming**: Database files are always named `<DBName>.mdf` and `<DBName>.ldf`, where `DBName` is read from config or defaults to `Settings.Default.DataPRO`.
|
||||
- **LocalDB Folder**: Database files reside in a subfolder named by `Settings.Default.LocalDbFolder` (e.g., `"LocalDB"`).
|
||||
- **File Extension Constants**: `.mdf` and `.ldf` extensions are defined in `Settings.Default.Mdf` and `Settings.Default.LogLdf`, respectively.
|
||||
- **DBType Parsing Fallback**: If `DBType` cannot be parsed from config, it defaults to `DbType.Local`.
|
||||
- **Copy Source Priority**: If a prior installation exists, source files are taken from the prior installation directory; otherwise, they are taken from the current `targetDir`.
|
||||
- **Return Value Semantics**:
|
||||
- `true`: Local DB preparation completed successfully (including no-op case where DB name matches default).
|
||||
- `false`: Either centralized DB mode, no prior installation found (when renaming is needed), or an early exit condition.
|
||||
|
||||
## 4. Dependencies
|
||||
|
||||
### External Dependencies (from imports):
|
||||
- `System.Configuration` (`ConfigurationManager`, `SettingElementCollection`, etc.)
|
||||
- `System.Data.SqlClient` (imported but *not used* in current code)
|
||||
- `Microsoft.Win32` (likely for registry access via `Common.PreviousInstall`)
|
||||
- `System.Security.Principal` (imported but *not used*)
|
||||
- `System.Windows.Forms` (used only for `MessageBox.Show` in `Main`)
|
||||
- `System.Threading` (imported but *not used*)
|
||||
- `LocalSQLDB.Properties.Settings` (strongly-typed settings from `Settings.Designer.cs`)
|
||||
|
||||
### Internal Dependencies:
|
||||
- `Common.PreviousInstall` (static class, not shown in source) — provides:
|
||||
- `GetMostRecentlyInstalledSubKeyName(Version, out string)`
|
||||
- `GetMostRecentlyInstalledPath(string subKeyName)`
|
||||
- `Settings.Default` (strongly-typed settings) — relies on:
|
||||
- `DataPRO`, `LocalDbFolder`, `Mdf`, `LogLdf`, `RegistryDataPROExe`, `ApplicationSettings`
|
||||
|
||||
### What Depends on This Module:
|
||||
- Windows Installer (via custom action executable `LocalSQLDB.exe`, presumably invoked during install sequence).
|
||||
- The DataPRO installer project (not shown) — this module is part of the `InstallerCustomActions` folder.
|
||||
|
||||
## 5. Gotchas
|
||||
|
||||
- **Static State in `LocalDBPrepare`**: Fields `_targetDir` and `_installingVersion` are `static`, meaning if multiple instances of `LocalDBPrepare` are created (e.g., in tests or concurrent invocations), they will share state — a potential source of race conditions or incorrect behavior. The class is instantiated once per run, but the design is fragile.
|
||||
- **Hardcoded Default DB Name**: Logic assumes `Settings.Default.DataPRO` is the canonical default database name; renaming only occurs if the configured name differs.
|
||||
- **Uncommented Code Paths**: Several lines of code are commented out (e.g., `//if (_newSettingsDictionary[ConfigSettings.DBCopy.ToString()])`), suggesting incomplete refactoring or legacy behavior. The current logic *always* falls back to copying from `targetDir` if no prior install exists — but the intent is unclear.
|
||||
- **No Validation of File Existence**: `File.Copy` is called without verifying the source files exist first. If `sourceFileName` points to a non-existent file, a `FileNotFoundException` will be thrown and caught by the top-level `try/catch`, causing installation failure.
|
||||
- **Exception Handling Obsfuscation**: The top-level `catch` in `Main` rethrows a *new* `Exception()` without preserving the original exception details (e.g., stack trace), making debugging difficult.
|
||||
- **Enum Parsing Fragility**: `Enum.TryParse` for `DbType` is case-sensitive by default; if the config value is `"local"` (lowercase) but the enum expects `"Local"`, it will fail and default to `DbType.Local`. This may be intentional, but is not documented.
|
||||
- **No Rollback on Partial Copy**: If copying the `.mdf` succeeds but the `.ldf` fails, the database files will be in an inconsistent state. No cleanup or rollback is attempted.
|
||||
- **Assumes LocalDB Folder Exists**: The code constructs paths using `Settings.Default.LocalDbFolder` but does not ensure the folder exists before copying files. `File.Copy` will throw if the directory is missing.
|
||||
- **Missing `using` for `System.IO`**: Though `System.IO.File.Copy` is used, `using System.IO;` is not declared — implying it is implicitly available (e.g., via other `using`s or project-level settings), but this is a potential portability issue.
|
||||
|
||||
None identified beyond those above.
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/LocalSQLDB/Properties/AssemblyInfo.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/LocalSQLDB/Properties/Settings.Designer.cs
|
||||
generated_at: "2026-04-16T04:45:12.575157+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "02e9f5ae4a239fa1"
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
## Documentation: LocalSQLDB Module
|
||||
|
||||
### 1. Purpose
|
||||
This module provides configuration and metadata for a local SQL Server database component used during Windows Installer custom actions in the DataPRO system. It does not contain executable installation logic itself but defines assembly identity and application-scoped settings that support database deployment operations—specifically, naming conventions and paths for database files (`.mdf`, `.ldf`) and registry keys. Its role is to centralize configuration constants used by other installer custom actions that interact with SQL Server Express or LocalDB instances.
|
||||
|
||||
### 2. Public Interface
|
||||
This module exposes **no public types or methods**. It defines only internal configuration and assembly metadata:
|
||||
|
||||
- **`LocalSQLDB.Properties.Settings`** (internal, sealed class)
|
||||
Auto-generated settings class (via `Settings.Designer.cs`) providing read-only, application-scoped configuration values. Accessible via `Settings.Default`.
|
||||
Properties:
|
||||
- `string RegistryDataPROExe` → `"DataPRO.exe"`
|
||||
Registry key path or executable name used to locate the DataPRO application.
|
||||
- `string ApplicationSettings` → `"applicationSettings"`
|
||||
Subkey or section name under which application settings are stored.
|
||||
- `string LocalDbFolder` → `"db"`
|
||||
Relative folder name where database files are stored.
|
||||
- `string Mdf` → `".mdf"`
|
||||
File extension for primary database files.
|
||||
- `string LogLdf` → `"_log.ldf"`
|
||||
Suffix used for transaction log files (note: full filename is constructed externally as `<basename><LogLdf>`).
|
||||
- `string DataPRO` → `"DataPRO"`
|
||||
Base name for database files (e.g., `DataPRO.mdf`, `DataPRO_log.ldf`).
|
||||
|
||||
> **Note**: The `Settings` class is `internal` and not part of the public API surface. Its properties are only consumed by other modules in the same assembly or via reflection.
|
||||
|
||||
### 3. Invariants
|
||||
- All settings are **application-scoped** and **read-only at runtime** (no user-scoped or mutable settings defined).
|
||||
- File naming convention: Database files follow the pattern `<DataPRO><Mdf>` and log files follow `<DataPRO><LogLdf>` (e.g., `DataPRO.mdf`, `DataPRO_log.ldf`).
|
||||
- `LocalDbFolder` is a relative subdirectory path; absolute paths are not used.
|
||||
- The assembly is **not COM-visible** (`ComVisible(false)`), indicating it is intended for .NET-only consumption.
|
||||
- Version is fixed at `1.0.0.0` (both `AssemblyVersion` and `AssemblyFileVersion`).
|
||||
|
||||
### 4. Dependencies
|
||||
- **Depends on**:
|
||||
- `System.Configuration` (for `ApplicationSettingsBase`, attributes like `ApplicationScopedSettingAttribute`)
|
||||
- `System.Runtime.CompilerServices`, `System.CodeDom.Compiler`, `System.Diagnostics` (for code generation attributes)
|
||||
- **Used by**:
|
||||
- Other modules in the `InstallerCustomActions` solution folder (e.g., custom action DLLs that perform database installation/uninstallation).
|
||||
- Likely consumed by installer projects (e.g., WiX, MSI) that reference this assembly for database file path resolution.
|
||||
- **No external runtime dependencies** beyond .NET Framework 4.0+ (inferred from runtime version in `Settings.Designer.cs`).
|
||||
|
||||
### 5. Gotchas
|
||||
- The `LogLdf` setting is a **suffix**, not a full filename—consumers must prepend the database name (e.g., `DataPRO` + `"_log.ldf"` = `"DataPRO_log.ldf"`). Confusing this with a full extension (e.g., assuming `".ldf"`) is a common mistake.
|
||||
- `RegistryDataPROExe` is named misleadingly: it holds `"DataPRO.exe"` (a filename), not a registry path. Actual registry key construction is handled elsewhere.
|
||||
- The `Settings` class is auto-generated and **should not be manually edited**—changes will be overwritten on regeneration.
|
||||
- No validation logic is present in this module; invalid file paths or naming conflicts are not caught here.
|
||||
- The assembly has no public entry points (e.g., no `CustomAction` classes defined here)—it is purely a configuration container.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/MigrateConfiguration/ConfigurationMigration.cs
|
||||
generated_at: "2026-04-16T04:43:59.723876+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "499179ba93465fb0"
|
||||
---
|
||||
|
||||
# MigrateConfiguration
|
||||
|
||||
## Documentation: `ConfigurationMigration.cs`
|
||||
|
||||
### 1. Purpose
|
||||
This module implements a configuration migration mechanism for DataPRO installer custom actions. Its primary role is to preserve user- and application-specific settings from the most recently installed previous version of DataPRO when a new version is installed, ensuring continuity of configuration without overwriting user-modified values with fresh defaults. It operates during installation by reading the old configuration file (if present), comparing settings against the new defaults, and migrating only those that differ (with special handling for `DownloadFolder` to avoid reverting to outdated defaults). It also handles migration of license files (`.lic`) from previous installations.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
The module is `internal static class ConfigurationMigration`. While not `public`, it exposes one method intended for use by the installer custom action infrastructure:
|
||||
|
||||
- **`UpdateConfigurationIfPossible(string targetDir, Version installingVersion, string setupExeDir, out string result)`**
|
||||
*Purpose:* Orchestrates configuration migration.
|
||||
*Behavior:*
|
||||
- Determines the most recently installed previous version using `PreviousInstall.GetMostRecentlyInstalledSubKeyName`.
|
||||
- Retrieves the installation path of that version via `PreviousInstall.GetMostRecentlyInstalledPath`.
|
||||
- Calls `MigrateLicenseFile` to copy license files.
|
||||
- Returns via `result` a status string indicating whether the config was updated, skipped, or failed.
|
||||
- Does **not** migrate `ApplicationSettings` or `UserSettings` sections itself—this appears to be omitted in the active code (commented out in `Main`). Only license migration is performed in the current implementation.
|
||||
|
||||
> **Note:** The `Main(string[] args)` method is `private static` and serves as the entry point for the custom action. It parses command-line arguments (`targetDir`, `installingVersion`, `noUI`, `setupExeDir`), initializes event logging, and calls `UpdateConfigurationIfPossible`. It also shows a `MessageBox` with migration results if `noUI != "TRUE"`.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **Version ordering:** Migration only occurs if a *strictly older* version is detected (`installingVersion` must be greater than the previously installed version).
|
||||
- **Path assumptions:**
|
||||
- The old config file is assumed to reside at `<oldInstallPath>\DataPRO.exe` (via `StringResources.RegistryDataPROExe`).
|
||||
- License files are searched up to **2 subdirectories deep** from either the current install directory (`setupExeDir`) or the old install path.
|
||||
- **Setting migration logic:**
|
||||
- A setting is migrated **only if**:
|
||||
1. It exists in both old and new config files.
|
||||
2. Its value in the old config differs from the *new default* (i.e., the value in the new config file before migration).
|
||||
3. **Exception for `DownloadFolder`:** It is *not* migrated if the old value equals `StringResources.DataUpOneLevel` (the old default), to avoid reverting to outdated paths.
|
||||
- **No partial migration of sections:** If `MigrateSettings` fails for either `UserSettings` or `ApplicationSettings`, the entire section is skipped.
|
||||
- **License file detection:** A file is considered a DataPRO license only if it is a `.lic` file containing both `<License>` and `<LicenseAttributes>` XML elements.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
**Internal dependencies (within module):**
|
||||
- `StringResources` (from `MigrateConfiguration.Resources`) — provides string constants (e.g., `DownloadFolder`, `UserSettings`, `ApplicationSettings`, `DataUpOneLevel`, `DataUpTwoLevels`, `ImportArchiveUpTwoLevels`, `DTSPlugins`, etc.).
|
||||
- `PreviousInstall` — used to query registry for previous installation metadata (`GetMostRecentlyInstalledSubKeyName`, `GetMostRecentlyInstalledPath`).
|
||||
- `ConfigInitializationHelper` — used in `MigrateSettings` via `GetNewSettings` (not shown in this file; inferred from usage).
|
||||
- `SettingElementCollection`, `SettingElement`, `ClientSettingsSection`, `Configuration` — from `System.Configuration`.
|
||||
|
||||
**External dependencies (imports):**
|
||||
- `System.Configuration`
|
||||
- `System.Windows.Forms` (for `MessageBox.Show`)
|
||||
- `System.IO`
|
||||
- `DTS.Common.Utilities`
|
||||
- `Installer.Common`
|
||||
|
||||
**Depended upon by:**
|
||||
- The Windows Installer custom action that invokes `ConfigurationMigration.Main(string[] args)` with command-line arguments.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **Critical omission:** The `Main` method contains **commented-out code blocks** that were intended to:
|
||||
- Pre-set `DownloadFolder` and `ImportArchiveFolder` to current defaults *before* migration.
|
||||
- Call `MigrateUserSettings` and `MigrateAppSettings` (via `UpdateConfigurationIfPossible` or directly).
|
||||
- Fix runtime module paths (`FixRunTimeModulesPath`).
|
||||
→ **As written, only license migration is active.** Configuration settings (`UserSettings`, `ApplicationSettings`) are *not* migrated in the current implementation.
|
||||
- **Hardcoded recursion depth:** `FindLicenseInPath` only searches 2 subdirectories deep (`subDirectoriesToCheck = 2`). Deeper nested license files will be missed.
|
||||
- **Assumption of default install paths:** `GetOldSettings` assumes the old config file is at `<oldInstallPath>\DataPRO.exe`. If the previous installation used a custom path, migration will fail.
|
||||
- **No rollback on failure:** If license copying fails, the error is reported but no cleanup or fallback occurs.
|
||||
- **Event logging is non-functional:** The `EventLog.Source` is set to `"MySource"` (hardcoded), but the source `"DataPROInstaller"` is created earlier. This mismatch may cause logging failures.
|
||||
- **`noUI` check is fragile:** `noUI != "TRUE"` is case-sensitive and exact. `"true"` or `"True"` would not suppress the UI.
|
||||
- **`SettingElementCollection` mutability:** The code removes and re-adds `SettingElement` instances to `newSettings`. This assumes `SettingElementCollection` allows modification after `Configuration` load, which may be fragile depending on .NET version or config file locking.
|
||||
- **Missing null checks:** `GetConfigSettings` accesses `configurationSectionGroup.Sections[0]` without verifying `Sections.Count > 0`, risking `IndexOutOfRangeException` if the section exists but is empty.
|
||||
|
||||
> **None identified from source alone** for *behavioral* quirks beyond the above — but the commented-out code strongly suggests this module is partially implemented or in a transitional state.
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/MigrateConfiguration/Properties/AssemblyInfo.cs
|
||||
generated_at: "2026-04-16T04:45:01.515164+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "9c70466a40d28903"
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
## Documentation Page: `MigrateConfiguration` Assembly
|
||||
|
||||
### 1. Purpose
|
||||
This module is an assembly named **`MigrateConfiguration`**, intended to support custom actions during installation processes—specifically, to handle migration of configuration data. Based on its placement in the `DataPRO/Modules/InstallerCustomActions/MigrateConfiguration/` directory structure, it serves as a dedicated component for configuration migration logic within a larger installer framework (likely Windows Installer-based, given the `CustomActions` context). The assembly itself contains no visible implementation code in the provided source file; it is purely an assembly metadata definition, suggesting the actual migration logic resides in other files (e.g., `CustomAction.cs`, `Migrator.cs`, etc.) not included here.
|
||||
|
||||
### 2. Public Interface
|
||||
**No public types, functions, or classes are defined in this file.**
|
||||
The provided source (`AssemblyInfo.cs`) contains only assembly-level attributes (e.g., title, version, COM visibility). It does not declare any public classes, interfaces, methods, or properties. Therefore, **no public interface elements can be documented from this file alone**.
|
||||
|
||||
### 3. Invariants
|
||||
- The assembly is **not visible to COM** (`ComVisible(false)`), meaning it is not intended for interop with COM clients.
|
||||
- The assembly version is fixed at `1.0.0.0` for both `AssemblyVersion` and `AssemblyFileVersion`.
|
||||
- The `Guid` attribute (`c255c030-ef08-4974-8654-969e29ab3b77`) uniquely identifies the typelib for COM exposure (though COM visibility is disabled, this GUID is still defined and may be used internally or by tooling).
|
||||
- The assembly title and product name are both `"MigrateConfiguration"`, indicating its intended role.
|
||||
|
||||
### 4. Dependencies
|
||||
- **Runtime dependencies**: This file imports `System.Reflection`, `System.Runtime.CompilerServices`, and `System.Runtime.InteropServices`, indicating it relies on standard .NET reflection and COM interop namespaces.
|
||||
- **Consumers**: Since this is an assembly metadata file, it does not directly declare dependencies on other modules. However, the *actual implementation* of the `MigrateConfiguration` assembly (in other, unprovided files) likely depends on installer-related libraries (e.g., `System.Configuration.Install`, Windows Installer XML (WiX) toolset, or custom installer action base classes).
|
||||
- **Dependents**: Other modules in the `DataPRO/Modules/InstallerCustomActions/` hierarchy (e.g., a main installer project or bootstrapper) are expected to reference this assembly to invoke its custom actions.
|
||||
|
||||
### 5. Gotchas
|
||||
- **No implementation logic is present in this file.** Developers may mistakenly assume this file contains migration logic; it is *only* metadata. Actual functionality resides elsewhere (e.g., in a `CustomAction` class in the same project).
|
||||
- The assembly version is hardcoded to `1.0.0.0` with no auto-increment (`1.0.*` is commented out). This may lead to versioning issues if updates are deployed without manually bumping the version.
|
||||
- `ComVisible(false)` is set, but a `Guid` is still provided. This is valid but unusual—ensure no legacy tooling expects COM visibility for this assembly.
|
||||
- No licensing, security, or threading model attributes are declared (e.g., `STAThreadAttribute`), which may be relevant if the assembly hosts custom actions in a UI context.
|
||||
- **None identified from source alone.** (Note: The above points are inferred from standard .NET conventions and the structure of `AssemblyInfo.cs`, not from explicit source behavior.)
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/MigrateConfiguration/Resources/StringResources.Designer.cs
|
||||
generated_at: "2026-04-16T04:45:05.933790+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "99758cb5d382b63b"
|
||||
---
|
||||
|
||||
# Resources
|
||||
|
||||
## Documentation: `StringResources` Class (`DataPRO/Modules/InstallerCustomActions/MigrateConfiguration/Resources/StringResources.Designer.cs`)
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
This module provides a strongly-typed, localized string resource accessor for the `MigrateConfiguration` installer custom action. It centralizes all user-facing messages related to configuration migration (e.g., status updates, warnings, errors) to support localization and maintain consistency across installer logic. The class is auto-generated from `.resx` resources and is not intended for manual modification.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
All members are `internal` (not `public`), but are exposed as static properties for use within the same assembly. The class is named `StringResources` in the `MigrateConfiguration.Resources` namespace.
|
||||
|
||||
| Property | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `ResourceManager` | `System.Resources.ResourceManager` | Returns a cached `ResourceManager` instance for the `MigrateConfiguration.Resources.StringResources` resource set. Thread-safe after first access. |
|
||||
| `Culture` | `System.Globalization.CultureInfo` | Gets or sets the UI culture used for resource lookups. Overrides the current thread's `CurrentUICulture` for this class. |
|
||||
| `ApplicationSettings` | `string` | Returns `"applicationSettings"` — likely the config section name for application-level settings. |
|
||||
| `ConfigDidNotNeedToBeUpdated` | `string` | Returns `"DataPRO.exe.config did not need to be updated."` |
|
||||
| `ConfigMigrationStatus` | `string` | Returns `"Config migration status."` — likely a log header. |
|
||||
| `ConfigWasUpdated` | `string` | Returns `"DataPRO.exe.config was updated from the {0} installation."` — format expects one argument (e.g., source version). |
|
||||
| `DataPROWin7PropertiesSettings` | `string` | Returns `"DataPROWin7.Properties.Settings."` — likely the user settings section name. |
|
||||
| `DataUpOneLevel` | `string` | Returns `"..\Data"` — relative path to data directory. |
|
||||
| `DataUpTwoLevels` | `string` | Returns `"..\..\Data"` — relative path to data directory (two levels up). |
|
||||
| `DownloadFolder` | `string` | Returns `"DownloadFolder"` — likely a config key name. |
|
||||
| `DTSCommonCorePluginLibConfig` | `string` | Returns `"DTS.Common.Core.PluginLib.Config"` — likely a config section name. |
|
||||
| `DTSPlugins` | `string` | Returns `"DTSPlugins"` — likely a config key name. |
|
||||
| `DTSPluginsNeedsModification` | `string` | Returns `"The 'DTSPlugins' key in DataPRO.exe.config must be manually changed to '..//RunTimeModules'."` |
|
||||
| `DTSViewerModules` | `string` | Returns `"DTSViewerModules"` — likely a config key name. |
|
||||
| `FailedToCopyLicense` | `string` | Returns `"Failed to copy license."` |
|
||||
| `ImportArchiveFolder` | `string` | Returns `"ImportArchiveFolder"` — likely a config key name. |
|
||||
| `ImportArchiveUpTwoLevels` | `string` | Returns `"..\..\ImportArchive"` — relative path. |
|
||||
| `InstallerLicenseFileFoundCopied` | `string` | Returns `"Installer license file found and copied."` |
|
||||
| `KeyNotFound` | `string` | Returns `"DTSPlugins key not found: {0}."` — format expects one argument (e.g., key name). |
|
||||
| `NewSettingsCouldNotBeFound` | `string` | Returns `"Warning: DataPRO.exe.config was not updated because config settings from new version of DataPRO could not be found: {0}; {1}."` — two arguments expected. |
|
||||
| `NewSettingsCouldNotBeProcessed` | `string` | Returns `"Warning: DataPRO.exe.config was not updated because config settings from new version of DataPRO could not be processed.."` |
|
||||
| `NoLicenseFound` | `string` | Returns `"No license found to copy."` |
|
||||
| `OldLicenseFoundCopied` | `string` | Returns `"Old license found and copied."` |
|
||||
| `OldSettingsCouldNotBeFound` | `string` | Returns `"Warning: DataPRO.exe.config was not updated because config settings from previously-installed version of DataPRO could not be found: {0}; {1}."` — two arguments expected. |
|
||||
| `OldSettingsCouldNotBeProcessed` | `string` | Returns `"Warning: DataPRO.exe.config was not updated because config settings from previously-installed version of DataPRO could not be processed.."` |
|
||||
| `RegistryDataPROExe` | `string` | Returns `"DataPRO.exe"` — likely a registry key name. |
|
||||
| `RunTimeModules` | `string` | Returns `"RunTimeModules"` — likely a config key name (target value for `DTSPlugins`). |
|
||||
| `SectionNotFound` | `string` | Returns `"DTS.Common.Core.PluginLib.Config section not found."` |
|
||||
| `SettingNotFound` | `string` | Returns `"Configuration setting not found: {0}."` — format expects one argument (e.g., setting name). |
|
||||
| `ThisSettingNeedsModification` | `string` | Returns `"The {0} setting in DataPRO.exe.config was not changed to {1}.."` — two arguments expected (old value, new value). |
|
||||
| `UserSettings` | `string` | Returns `"userSettings"` — likely the config section name for user-level settings. |
|
||||
|
||||
> **Note**: All string properties are read-only and perform a lookup via `ResourceManager.GetString(...)`. None accept parameters directly; formatting is done by the caller.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
- The class is **thread-safe for read-only access** to `ResourceManager` (due to null-check-and-assign pattern in the getter), but `Culture` is not thread-safe when set concurrently.
|
||||
- Resource keys (e.g., `"ApplicationSettings"`, `"DTSPlugins"`) are assumed to exist in the underlying `.resx` file; missing keys would cause a `MissingManifestResourceException` at runtime (not caught in this class).
|
||||
- The class is **not meant to be instantiated**; the constructor is `internal` and only used by the runtime.
|
||||
- All string values are **static after first access**; no runtime mutation of the returned strings occurs.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
- **Depends on**:
|
||||
- `System.Resources.ResourceManager`
|
||||
- `System.Globalization.CultureInfo`
|
||||
- `System.CodeDom.Compiler`, `System.Diagnostics`, `System.Runtime.CompilerServices`, `System.ComponentModel` (for attributes)
|
||||
- The compiled assembly containing the `.resx` resources (same assembly as `StringResources` type).
|
||||
- **Used by**:
|
||||
- The `MigrateConfiguration` installer custom action module (inferred from namespace and file path).
|
||||
- Likely consumed by other classes in `MigrateConfiguration` (e.g., custom action logic that logs or displays messages during config migration).
|
||||
- **Not used by**:
|
||||
- Runtime application code (outside installer context), as the namespace and path suggest installer-specific usage.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
- **Auto-generated**: Manual edits will be overwritten. Changes must be made in the source `.resx` file.
|
||||
- **No error handling**: Resource lookup failures (e.g., missing key) will throw exceptions at runtime; callers must handle or expect crashes.
|
||||
- **Hardcoded paths**: Paths like `..\Data` and `..\..\Data` are hardcoded strings — their correctness depends on the installer’s working directory and deployment layout.
|
||||
- **Inconsistent formatting**: Some messages include trailing periods (`.`), others do not (e.g., `ConfigDidNotNeedToBeUpdated` vs `ConfigMigrationStatus`).
|
||||
- **Typo in path separator**: `DTSPluginsNeedsModification` uses `'..//RunTimeModules'` (double slash), which may be unintentional.
|
||||
- **Ambiguous keys**: Several keys (e.g., `DownloadFolder`, `ImportArchiveFolder`) are likely config *keys*, not values — but the class provides no distinction. Callers must know the context.
|
||||
- **No localization fallback logic**: If `Culture` is set to a language without resources, `ResourceManager` may fall back to invariant culture — behavior is standard but not explicit here.
|
||||
|
||||
> **None identified from source alone** beyond the above — no evidence of deprecated APIs, legacy workarounds, or known bugs beyond the noted inconsistencies.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/OpenFolder/App.xaml.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/OpenFolder/Folder.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/OpenFolder/MainWindow.xaml.cs
|
||||
generated_at: "2026-04-16T04:43:41.781372+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "01467cfc72ba0a69"
|
||||
---
|
||||
|
||||
# OpenFolder
|
||||
|
||||
## Documentation: `OpenFolder` Module
|
||||
|
||||
### 1. Purpose
|
||||
The `OpenFolder` module is a minimal WPF application intended to serve as a custom action during installation, specifically to open the *Manuals* folder for the installed product. It acts as a standalone executable invoked by the installer (e.g., WiX or MSI), accepting a single command-line argument (likely a product-specific path or identifier) and delegating folder opening logic to `WindowsFolder.OpenManualsFolder`. Due to its role as an installer custom action, it prioritizes simplicity and failure resilience over user interaction—evidenced by its silent exception handling and lack of UI interaction in the `Main` entry point.
|
||||
|
||||
### 2. Public Interface
|
||||
*No public types or methods are exposed.*
|
||||
All classes (`App`, `MainWindow`, `Folder`) and the `Main` method are internal (`class` without `public` modifier, `private static void Main`). The module does not define any public API surface beyond being an executable entry point.
|
||||
|
||||
- **`OpenFolder.App`**
|
||||
- *Type:* `partial class App : Application`
|
||||
- *Behavior:* Standard WPF `Application` class; no custom logic beyond initialization. Used for application lifecycle management (e.g., startup/shutdown events), but none are implemented in the provided source.
|
||||
|
||||
- **`OpenFolder.MainWindow`**
|
||||
- *Type:* `partial class MainWindow : Window`
|
||||
- *Behavior:* WPF window class with a parameterless constructor that calls `InitializeComponent()`. No UI logic, event handlers, or data binding are defined in the source. Likely unused in the installer context, as execution begins at `Folder.Main`.
|
||||
|
||||
- **`OpenFolder.Folder.Main(string[] args)`**
|
||||
- *Signature:* `private static void Main(string[] args)`
|
||||
- *Behavior:* Entry point for the executable. Invokes `WindowsFolder.OpenManualsFolder(args[0])` with the first command-line argument. Any exceptions during execution are silently caught and ignored (no logging or error reporting).
|
||||
|
||||
### 3. Invariants
|
||||
- **Command-line argument requirement:** The `Main` method assumes `args.Length ≥ 1`; accessing `args[0]` without bounds checking will throw an `IndexOutOfRangeException` if no arguments are provided.
|
||||
- **Silent failure:** All exceptions in `Main` are suppressed; no indication of success/failure is returned to the caller (e.g., installer). Exit code is implicitly `0` (success), even if `OpenManualsFolder` fails.
|
||||
- **No UI interaction:** The `MainWindow` is never shown or referenced in `Main`, confirming the module is designed to run headlessly as an installer custom action.
|
||||
- **Dependency on external library:** Behavior relies entirely on `WindowsFolder.OpenManualsFolder`, whose contract (e.g., expected argument format, folder resolution logic) is defined elsewhere (in `DTS.Common.Classes.WindowsFolders`).
|
||||
|
||||
### 4. Dependencies
|
||||
- **External dependency:**
|
||||
- `DTS.Common.Classes.WindowsFolders.WindowsFolder` (from `DTS.Common.dll`): Provides the `OpenManualsFolder(string)` method. Its implementation determines the actual folder path resolution (e.g., using environment variables, registry keys, or installation paths).
|
||||
- **WPF framework dependencies:**
|
||||
- `System.Windows`, `System.Windows.Controls`, etc. (via `PresentationFramework`, `PresentationCore`, `WindowsBase`).
|
||||
- **No internal dependencies:**
|
||||
- No other modules or files in the codebase are referenced or imported.
|
||||
- **Depended on by:**
|
||||
- The installer (e.g., WiX `CustomAction` or MSI `CustomAction` table) that invokes this executable during installation. The installer is expected to pass the required argument (e.g., installation directory or product ID) to `args[0]`.
|
||||
|
||||
### 5. Gotchas
|
||||
- **No argument validation:** The `Main` method directly accesses `args[0]` without checking `args.Length`, risking a crash if invoked without arguments.
|
||||
- **Silent error suppression:** Exceptions (e.g., `IndexOutOfRangeException`, `IOException`, `SecurityException`) are caught and ignored, making debugging difficult. Installers relying on exit codes or logs will not detect failures.
|
||||
- **Unused WPF components:** The `App.xaml`, `MainWindow.xaml`, and related WPF infrastructure are present but unused in the `Main` flow. This suggests the module may have evolved from a UI-based tool to a headless custom action, leaving dead code.
|
||||
- **Ambiguous argument semantics:** The purpose of `args[0]` is not documented in the source. It is unclear whether it represents a base path, product ID, or configuration key—this must be inferred from `WindowsFolder.OpenManualsFolder`’s implementation.
|
||||
- **No explicit exit code:** The process exits with the default code (`0`) regardless of success/failure, which may mislead installers expecting non-zero codes on error.
|
||||
|
||||
*None identified from source alone.*
|
||||
*(Note: The above "Gotchas" are derived from explicit code patterns; no external assumptions beyond the provided source are made.)*
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/OpenFolder/Properties/Settings.Designer.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/OpenFolder/Properties/AssemblyInfo.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/OpenFolder/Properties/Resources.Designer.cs
|
||||
generated_at: "2026-04-16T04:44:44.073191+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "e5c3297c1a5efb68"
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
## Documentation: `OpenFolder` Module (Installer Custom Action)
|
||||
|
||||
---
|
||||
|
||||
### 1. **Purpose**
|
||||
|
||||
This module is a .NET assembly (`OpenFolder`) intended for use as a Windows Installer custom action, specifically to support opening a folder (likely during or after installation). It contains only auto-generated infrastructure files—no custom logic is present in the provided source. Its role is to define assembly metadata, strongly-typed settings (via `ApplicationSettingsBase`), and localized resources (via `ResourceManager`), serving as a supporting component in the larger `DataPRO` installer ecosystem.
|
||||
|
||||
---
|
||||
|
||||
### 2. **Public Interface**
|
||||
|
||||
The module exposes only auto-generated infrastructure types. No custom public APIs are defined in the provided files.
|
||||
|
||||
- **`OpenFolder.Properties.Settings`**
|
||||
- *Type*: `internal sealed partial class Settings : ApplicationSettingsBase`
|
||||
- *Behavior*: Provides a singleton `Default` property returning a thread-safe `Settings` instance. No custom settings properties are defined in the source—only the base infrastructure is present.
|
||||
- *Note*: The class is `internal`, so it is not directly accessible outside the assembly unless exposed via another public type (not present here).
|
||||
|
||||
- **`OpenFolder.Properties.Resources`**
|
||||
- *Type*: `internal sealed partial class Resources`
|
||||
- *Behavior*: Provides strongly-typed access to localized resources via `ResourceManager` and `Culture` properties. No resource keys or values are defined in the source—only the infrastructure for resource lookup.
|
||||
- *Note*: Also `internal`, and no public methods or properties beyond `ResourceManager` and `Culture` are exposed.
|
||||
|
||||
- **Assembly-level attributes** (via `AssemblyInfo.cs`)
|
||||
- *Examples*:
|
||||
- `AssemblyTitle("OpenFolder")`
|
||||
- `AssemblyVersion("1.0.0.0")`
|
||||
- `ComVisible(false)`
|
||||
- `ThemeInfo(...)` for WPF resource location
|
||||
- *Behavior*: These are metadata attributes used by the .NET runtime and tooling; they do not define executable behavior.
|
||||
|
||||
---
|
||||
|
||||
### 3. **Invariants**
|
||||
|
||||
- The `Settings.Default` property always returns a synchronized singleton instance (via `ApplicationSettingsBase.Synchronized`), ensuring thread-safe access.
|
||||
- The `Resources.ResourceManager` is lazily initialized on first access and cached in a static field.
|
||||
- The assembly is marked `ComVisible(false)`, meaning its types are not exposed to COM by default.
|
||||
- No runtime validation or business logic is present in the provided files—no invariants beyond those of the base classes (`ApplicationSettingsBase`, `ResourceManager`) apply.
|
||||
|
||||
---
|
||||
|
||||
### 4. **Dependencies**
|
||||
|
||||
- **Dependencies *of* this module**:
|
||||
- `System.Configuration` (for `ApplicationSettingsBase`)
|
||||
- `System.Resources` (for `ResourceManager`, `Resources`)
|
||||
- `System.Globalization` (for `CultureInfo`)
|
||||
- `System.Windows` (for `ThemeInfo` attribute usage—though no WPF UI is evident here)
|
||||
- `System.Runtime.CompilerServices`, `System.CodeDom.Compiler`, `System.Diagnostics`, `System.ComponentModel` (for attributes and tooling support)
|
||||
|
||||
- **Dependencies *on* this module**:
|
||||
- Not inferable from the provided files. As a custom action module, it is likely referenced by an MSI project or installer build pipeline, but no such references appear in the source.
|
||||
|
||||
---
|
||||
|
||||
### 5. **Gotchas**
|
||||
|
||||
- **No custom logic present**: The module contains *only* auto-generated infrastructure. Any functional behavior (e.g., actually opening a folder) must reside in other files *not provided*—likely in a custom action class (e.g., `Installer.cs` or similar) in the same project.
|
||||
- **`internal` visibility**: All public-facing types (`Settings`, `Resources`) are `internal`, meaning they cannot be accessed from outside the assembly unless explicitly exposed via `InternalsVisibleTo` (not present in `AssemblyInfo`).
|
||||
- **Empty settings/resources**: The `Settings` class has no user-defined properties, and `Resources` has no defined resource members—suggesting either incomplete implementation or that these are placeholders for future use.
|
||||
- **Auto-generated warning**: Both `Settings.Designer.cs` and `Resources.Designer.cs` explicitly warn that manual changes will be lost on regeneration. This implies the project relies on Visual Studio’s designer tooling for future edits.
|
||||
- **Versioning**: Assembly version is hardcoded to `1.0.0.0` (with `AssemblyFileVersion` same), which may be intentional for installer stability or indicate a lack of version tracking discipline.
|
||||
|
||||
None identified beyond the above.
|
||||
@@ -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 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.*
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/RegAddProductCode/Properties/AssemblyInfo.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/RegAddProductCode/Properties/Settings.Designer.cs
|
||||
generated_at: "2026-04-16T04:44:25.291700+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "c5bd9c265d48c4b1"
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
## Documentation: `RegAddProductCode` Module
|
||||
|
||||
### 1. Purpose
|
||||
This module is a .NET-based Windows Installer custom action designed to register a product code in a specific Windows Registry location—primarily to support Windows Installer’s `SecureRepairPolicy` mechanism. It reads configuration settings (including registry key paths and a product code GUID) and writes the product code to the `SecureRepairWhitelist` registry subkey under the Windows Installer policies path. Its role is to ensure that a given product remains whitelisted for secure repair operations, a security feature introduced in Windows Installer to restrict which products may be repaired without elevated privileges.
|
||||
|
||||
### 2. Public Interface
|
||||
No public *executable* API (e.g., `CustomAction` entry points) is visible in the provided source files. However, the module exposes the following *configuration* types and members:
|
||||
|
||||
- **`RegAddProductCode.Properties.Settings.Default`**
|
||||
- **Type**: `RegAddProductCode.Properties.Settings` (singleton instance)
|
||||
- **Behavior**: Provides application-scoped read-only access to configuration values defined in `Settings.settings`. This is the only public surface exposed via the generated settings class.
|
||||
|
||||
- **`RegAddProductCode.Properties.Settings.InstallerKey`**
|
||||
- **Type**: `string`
|
||||
- **Default Value**: `"SOFTWARE\\Policies\\Microsoft\\Windows\\Installer"`
|
||||
- **Behavior**: Returns the base registry key path for Windows Installer policies.
|
||||
|
||||
- **`RegAddProductCode.Properties.Settings.MissingKey`**
|
||||
- **Type**: `string`
|
||||
- **Default Value**: `"No key at {0}"`
|
||||
- **Behavior**: A format string template, likely intended for logging or error messages when a registry key is not found.
|
||||
|
||||
- **`RegAddProductCode.Properties.Settings.ProductCode`**
|
||||
- **Type**: `string`
|
||||
- **Default Value**: `"{C4889149-0CAF-44C1-B226-8F6E73684DF4}"`
|
||||
- **Behavior**: Returns the product code GUID to be added to the whitelist.
|
||||
|
||||
- **`RegAddProductCode.Properties.Settings.SecureRepairPolicy`**
|
||||
- **Type**: `string`
|
||||
- **Default Value**: `"SecureRepairPolicy"`
|
||||
- **Behavior**: The name of the registry value used to enable/disable secure repair policy.
|
||||
|
||||
- **`RegAddProductCode.Properties.Settings.SecureRepairWhitelistKey`**
|
||||
- **Type**: `string`
|
||||
- **Default Value**: `"SOFTWARE\\Policies\\Microsoft\\Windows\\Installer\\SecureRepairWhitelist"`
|
||||
- **Behavior**: Returns the full registry path where whitelisted product codes are stored.
|
||||
|
||||
> **Note**: The actual custom action logic (e.g., `Install`/`Commit`/`Rollback` methods or `[CustomAction]`-attributed functions) is *not present* in the provided files and must reside in other source files (e.g., `CustomAction.cs`). This documentation is limited to what is exposed in the provided `AssemblyInfo.cs` and `Settings.Designer.cs`.
|
||||
|
||||
### 3. Invariants
|
||||
- The `ProductCode` setting is expected to be a valid GUID string (format `{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}`), though no runtime validation is evident from the settings definition.
|
||||
- The registry paths (`InstallerKey`, `SecureRepairWhitelistKey`) are hardcoded and must be valid Windows Registry paths (double-escaped backslashes in source reflect single escaping in the runtime string).
|
||||
- Settings are *application-scoped* and read-only at runtime (no setters exposed); they are fixed at compile time.
|
||||
- The `Settings.Default` instance is thread-safe via `ApplicationSettingsBase.Synchronized()`.
|
||||
|
||||
### 4. Dependencies
|
||||
- **Runtime Dependencies**:
|
||||
- `System.Configuration.dll` (for `ApplicationSettingsBase`, `ApplicationScopedSettingAttribute`, etc.)
|
||||
- `System.dll` (for core types like `string`, `Attribute`, etc.)
|
||||
- **Build/Deployment Dependencies**:
|
||||
- This assembly is likely referenced by a Windows Installer (MSI) project or custom action project (e.g., WiX, InstallShield) as a custom action DLL.
|
||||
- It depends on the Windows Installer service being available at runtime (to interact with registry policy keys).
|
||||
- **Inferred Consumers**:
|
||||
- An external installer project (e.g., `.wixproj`, `.vdproj`) that invokes this assembly as a custom action during installation/repair.
|
||||
- The `RegAddProductCode` assembly itself is not referenced programmatically by other modules in the provided source.
|
||||
|
||||
### 5. Gotchas
|
||||
- **Missing Custom Action Entry Point**: The provided files contain *no* `CustomAction` method definitions (e.g., no `[CustomAction]` attributes or `Session`-based logic). The actual behavior (reading settings and writing to registry) is not observable here—this module’s *purpose* is inferred from naming and settings, but implementation details are absent.
|
||||
- **Hardcoded Product Code**: The `ProductCode` is fixed at compile time (`{C4889149-0CAF-44C1-B226-8F6E73684DF4}`), meaning this assembly is not reusable for other products without recompilation.
|
||||
- **Registry Path Escaping**: The `\\` in string literals (e.g., `"SOFTWARE\\\\Policies..."`) are *literal* backslashes in the compiled string (due to C# escaping), which is correct for registry paths, but could be confusing if misread.
|
||||
- **No Error Handling in Settings**: The settings class provides no mechanism to validate or handle missing registry keys—error handling (e.g., for `MissingKey`) must be implemented elsewhere (e.g., in the custom action logic not shown).
|
||||
- **No Versioning Strategy**: Assembly version is `1.0.0.0` for both `AssemblyVersion` and `AssemblyFileVersion`, suggesting minimal version discipline—could cause issues in side-by-side deployments.
|
||||
- **None identified from source alone.** (Additional gotchas would require inspecting the actual custom action implementation.)
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/WarnWindows11/WarnWindows11.cs
|
||||
generated_at: "2026-04-16T04:43:22.817107+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "4bf07a16db262f9c"
|
||||
---
|
||||
|
||||
# WarnWindows11
|
||||
|
||||
## 1. Purpose
|
||||
This module provides a Windows Installer custom action that warns users during installation if the target system is running Windows 11. It executes as part of the installation sequence, checks the OS version by parsing the output of `systeminfo.exe`, and displays a modal warning message box if Windows 11 is detected—aimed at alerting users to potential compatibility concerns (as implied by the resource key `WARNING_WINDOWS11`). It exists to proactively inform users before proceeding with installation on an unsupported or untested platform.
|
||||
|
||||
## 2. Public Interface
|
||||
- **`OSWarning.Main(string[] args)`**
|
||||
*Signature:* `public static void Main(string[] args)`
|
||||
*Behavior:* Entry point for the custom action. Launches `systeminfo.exe`, captures its standard output, and scans line-by-line for the substring `"MICROSOFT WINDOWS 11"` (case-insensitive). If found, displays a message box using `Properties.Resources.WARNING_WINDOWS11`. All exceptions are silently caught and ignored; no error reporting or logging occurs.
|
||||
|
||||
## 3. Invariants
|
||||
- The process must successfully spawn `systeminfo.exe` and read its full output synchronously before proceeding.
|
||||
- The OS detection relies *solely* on exact substring matching in `systeminfo.exe` output; no other version-checking mechanisms (e.g., `Environment.OSVersion`, registry queries) are used.
|
||||
- The message box is shown *only* if the substring `"MICROSOFT WINDOWS 11"` appears anywhere in the output (case-insensitive).
|
||||
- No return value or exit code is set; the method always exits normally (even on failure).
|
||||
- The custom action assumes it runs in an interactive context (since `MessageBox.Show` requires user interaction); non-interactive execution (e.g., silent install) may hang or fail silently.
|
||||
|
||||
## 4. Dependencies
|
||||
- **Runtime:** .NET Framework (uses `System.Windows.Forms.MessageBox`, `System.Diagnostics.Process`, `System` namespaces).
|
||||
- **External executable:** `systeminfo.exe` (standard Windows utility; must be present on the target system).
|
||||
- **Resources:** `Properties.Resources.WARNING_WINDOWS11` must be defined (string resource) in the same assembly; failure to define it would cause a compile-time error.
|
||||
- **Caller:** Intended to be invoked as a Windows Installer custom action (likely deferred or immediate, though not specified here).
|
||||
- **No external libraries** beyond the base .NET Framework.
|
||||
|
||||
## 5. Gotchas
|
||||
- **Fragile OS detection:** Relies on `systeminfo.exe` output format, which may vary across Windows versions, locales, or system configurations (e.g., localized output like `"Microsoft Windows 11 Pro"` vs. `"Microsoft Windows 11"`).
|
||||
- **Silent failure handling:** All exceptions (including `Win32Exception` if `systeminfo.exe` is missing, `InvalidOperationException` if process fails, or `SecurityException` if permissions are insufficient) are swallowed—no diagnostics or fallback behavior.
|
||||
- **Blocking UI call:** `MessageBox.Show` blocks the installer thread; if invoked non-interactively (e.g., via `msiexec /quiet`), the installer may hang indefinitely waiting for user input.
|
||||
- **No cancellation path:** The warning is informational only; the installation proceeds regardless of whether the user dismisses the message.
|
||||
- **Performance:** Synchronous process execution and full output parsing may add latency to installation (though `systeminfo.exe` is typically fast).
|
||||
- **No version validation:** Detects *any* Windows 11 variant (Home, Pro, etc.) but does not distinguish editions or build numbers.
|
||||
- **Missing resource handling:** If `Properties.Resources.WARNING_WINDOWS11` is null or empty, the message box will show an empty dialog—no null check is performed.
|
||||
- **Case-insensitivity is applied only to the search string, not the output:** The `line.ToUpper()` call ensures case-insensitive matching of `"MICROSOFT WINDOWS 11"`, but if `systeminfo.exe` output uses non-ASCII characters (e.g., accented letters), matching may still fail.
|
||||
- **No cleanup of process resources beyond `WaitForExit()`:** While `using` ensures disposal of the `Process` object, there is no explicit handling of `StandardOutput` stream disposal (though `reader.ReadToEnd()` closes it implicitly).
|
||||
|
||||
*None identified from source alone.* → **Correction:** Several gotchas *are* apparent from the source (see above).
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
source_files:
|
||||
- DataPRO/Modules/InstallerCustomActions/WarnWindows11/Properties/Settings.Designer.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/WarnWindows11/Properties/AssemblyInfo.cs
|
||||
- DataPRO/Modules/InstallerCustomActions/WarnWindows11/Properties/Resources.Designer.cs
|
||||
generated_at: "2026-04-16T04:44:32.111058+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "136a291046e5df64"
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
## Documentation: `WarnWindows11` Module
|
||||
|
||||
### 1. Purpose
|
||||
This module provides a localized warning message used during SQL Server installation on Windows 11, alerting users to potential manual steps required due to OS-specific disk sector size constraints. It exists as a self-contained assembly intended for use in Windows Installer custom actions—specifically to surface a predefined warning string via resource lookup. The module does not contain executable logic beyond exposing the warning text; it is purely a resource container.
|
||||
|
||||
### 2. Public Interface
|
||||
The module exposes no public *types* beyond internal auto-generated classes. However, the following public members are accessible *within the assembly* (and may be consumed by external callers via reflection or strong-named referencing, though not designed for direct public use):
|
||||
|
||||
- **`WarnWindows11.Properties.Settings.Default`**
|
||||
- *Type:* `WarnWindows11.Properties.Settings` (singleton, sealed, derived from `ApplicationSettingsBase`)
|
||||
- *Behavior:* Provides access to the application settings instance for this assembly. No custom settings are defined in the source—only the default singleton accessor is present.
|
||||
|
||||
- **`WarnWindows11.Properties.Resources.WARNING_WINDOWS11`**
|
||||
- *Type:* `string` (read-only property)
|
||||
- *Behavior:* Returns the localized warning string:
|
||||
> *"Installation of Microsoft SQL Server on windows 11 may require some manual steps to run. See https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/database-file-operations/troubleshoot-os-4kb-disk-sector-size for more information, or contact DTS support for assistance."*
|
||||
This is the only resource string defined and is the sole functional output of the module.
|
||||
|
||||
- **`WarnWindows11.Properties.Resources.ResourceManager`**
|
||||
- *Type:* `System.Resources.ResourceManager` (read-only property)
|
||||
- *Behavior:* Lazily initializes and returns a `ResourceManager` instance bound to the `"WarnWindows11.Properties.Resources"` base name within the current assembly.
|
||||
|
||||
- **`WarnWindows11.Properties.Resources.Culture`**
|
||||
- *Type:* `System.Globalization.CultureInfo` (read/write property)
|
||||
- *Behavior:* Allows overriding the thread’s `CurrentUICulture` for resource lookups. Defaults to `null`, meaning `ResourceManager` uses the current UI culture.
|
||||
|
||||
### 3. Invariants
|
||||
- The `Settings.Default` property always returns the same singleton instance (enforced via `Synchronized()` and static field initialization).
|
||||
- `Resources.WARNING_WINDOWS11` always returns the exact string literal defined in `Resources.resx` (as reflected in `Resources.Designer.cs`).
|
||||
- The `ResourceManager` is initialized exactly once per AppDomain (lazy initialization with null-check).
|
||||
- The assembly is non-`ComVisible` (`[ComVisible(false)]`), meaning its types are not exposed to COM by default.
|
||||
- No runtime validation or conditional logic is present—the warning string is static and unconditionally returned.
|
||||
|
||||
### 4. Dependencies
|
||||
- **Runtime Dependencies:**
|
||||
- `System.Configuration` (for `ApplicationSettingsBase`)
|
||||
- `System.Resources` (for `ResourceManager`, `Resources`)
|
||||
- `System.Globalization` (for `CultureInfo`)
|
||||
- `System.Windows` (referenced via `System.Windows.dll`, implied by `System.Windows` namespace usage in `AssemblyInfo.cs`; likely for WPF-based installer UI, though not directly used here)
|
||||
- **Assembly Dependencies (inferred):**
|
||||
- `WarnWindows11` assembly itself (self-contained).
|
||||
- No external project or library dependencies are declared in the provided files.
|
||||
- **Consumers (inferred):**
|
||||
- Likely consumed by a Windows Installer custom action (e.g., in a `.wixproj` or custom action DLL) that displays this warning during SQL Server installation on Windows 11.
|
||||
- May be referenced by other installer modules (e.g., `DataPRO.InstallerCustomActions`) via strong-named assembly reference.
|
||||
|
||||
### 5. Gotchas
|
||||
- **No custom settings defined**: Though `Settings.Designer.cs` exists, the `Settings` class contains no user-defined properties—only the default accessor. Any expectation of configurable behavior (e.g., warning thresholds, URLs) is unfounded.
|
||||
- **Hardcoded URL**: The warning string embeds a specific Microsoft support URL. If this URL changes or becomes stale, the warning becomes outdated and requires recompilation.
|
||||
- **Case sensitivity in resource key**: The property `WARNING_WINDOWS11` corresponds to a resource key `"WARNING_WINDOWS11"` in the `.resx` file. Any mismatch in casing or spelling between `.resx` and the generated code would cause a runtime `MissingManifestResourceException`.
|
||||
- **Auto-generated code**: Both `Settings.Designer.cs` and `Resources.Designer.cs` are auto-generated. Manual edits will be overwritten; changes must be made in the designer (`.resx`, `.settings`) or `.csproj` files.
|
||||
- **No localization logic in source**: While `Culture` and `ResourceManager` are present, no `.resx` fallback or satellite assemblies are visible in the provided files. Localization is assumed but unverified from source alone.
|
||||
- **Assembly version fixed at `1.0.0.0`**: Both `AssemblyVersion` and `FileVersion` are hardcoded to `1.0.0.0`, which may complicate versioning in deployment pipelines.
|
||||
Reference in New Issue
Block a user