diff --git a/.editorconfig b/.editorconfig
index 631b04b..342d7c2 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -525,9 +525,11 @@ dotnet_diagnostic.IDE0079.severity = none # dotnet_remove_unnecessary_
dotnet_diagnostic.MA0134.severity = none # Observe result of async calls
+dotnet_diagnostic.S2629.severity = none # Don't use string interpolation in logging message templates.
dotnet_diagnostic.S3267.severity = none # Loops should be simplified with 'LINQ' expressions
dotnet_diagnostic.S4487.severity = none # Remove this unread private field
dotnet_diagnostic.S6602.severity = none # "Find" method should be used instead of the "FirstOrDefault"
dotnet_diagnostic.S6605.severity = none # Collection-specific "Exists" method should be used instead of the "Any"
+dotnet_diagnostic.S6667.severity = none # Logging in a catch clause should pass the caught exception as a parameter.
dotnet_diagnostic.SCS0006.severity = none # Do Not Use Broken Cryptographic Algorithms - Its ok, only using to calculate a file-hash
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index 53f57da..3f80a19 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -44,7 +44,7 @@
-
+
\ No newline at end of file
diff --git a/src/Atc.Installer.Integration/Enums/HostingFrameworkType.cs b/src/Atc.Installer.Integration/Enums/HostingFrameworkType.cs
index 8858b58..fa438c3 100644
--- a/src/Atc.Installer.Integration/Enums/HostingFrameworkType.cs
+++ b/src/Atc.Installer.Integration/Enums/HostingFrameworkType.cs
@@ -12,7 +12,7 @@ public enum HostingFrameworkType
NativeNoSettings,
[Description(".NET Framework 4.8")]
- DonNetFramework48,
+ DotNetFramework48,
[Description(".NET 7")]
DotNet7,
diff --git a/src/Atc.Installer.Integration/Helpers/RegistryHelper.cs b/src/Atc.Installer.Integration/Helpers/RegistryHelper.cs
new file mode 100644
index 0000000..6b20c0f
--- /dev/null
+++ b/src/Atc.Installer.Integration/Helpers/RegistryHelper.cs
@@ -0,0 +1,82 @@
+namespace Atc.Installer.Integration.Helpers;
+
+[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "OK.")]
+[SupportedOSPlatform("Windows")]
+public static class RegistryHelper
+{
+ public static (bool IsSucceeded, string? ErrorMessage) CreateSubKeyInLocalMachine(
+ string key)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(key);
+
+ try
+ {
+ using var registryKey = Registry.LocalMachine.CreateSubKey(key);
+ if (registryKey is null)
+ {
+ return (false, $"Registry-LocalMachine-CreateSubKey: {key}");
+ }
+ }
+ catch (Exception ex)
+ {
+ return (false, $"Registry-LocalMachine-CreateSubKey: {key} - {ex.Message}");
+ }
+
+ return (true, null);
+ }
+
+ public static (bool IsSucceeded, string? ErrorMessage) DeleteSubKeyTreeInLocalMachine(
+ string key)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(key);
+
+ try
+ {
+ Registry.LocalMachine.DeleteSubKeyTree(key, throwOnMissingSubKey: false);
+ }
+ catch (Exception ex)
+ {
+ return (false, $"Registry-LocalMachine-DeleteSubKeyTree: {key} - {ex.Message}");
+ }
+
+ return (true, null);
+ }
+
+ public static (bool IsSucceeded, string? ErrorMessage) CreateSubKeyInCurrentUser(
+ string key)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(key);
+
+ try
+ {
+ using var registryKey = Registry.CurrentUser.CreateSubKey(key);
+ if (registryKey is null)
+ {
+ return (false, $"Registry-CurrentUser-CreateSubKey: {key}");
+ }
+ }
+ catch (Exception ex)
+ {
+ return (false, $"Registry-CurrentUser-CreateSubKey: {key} - {ex.Message}");
+ }
+
+ return (true, null);
+ }
+
+ public static (bool IsSucceeded, string? ErrorMessage) DeleteSubKeyTreeInCurrentUser(
+ string key)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(key);
+
+ try
+ {
+ Registry.CurrentUser.DeleteSubKeyTree(key, throwOnMissingSubKey: false);
+ }
+ catch (Exception ex)
+ {
+ return (false, $"Registry-CurrentUser-DeleteSubKeyTree: {key} - {ex.Message}");
+ }
+
+ return (true, null);
+ }
+}
\ No newline at end of file
diff --git a/src/Atc.Installer.Integration/InstallationConfigurations/ApplicationOption.cs b/src/Atc.Installer.Integration/InstallationConfigurations/ApplicationOption.cs
index b30ad4c..0c768a7 100644
--- a/src/Atc.Installer.Integration/InstallationConfigurations/ApplicationOption.cs
+++ b/src/Atc.Installer.Integration/InstallationConfigurations/ApplicationOption.cs
@@ -26,6 +26,8 @@ public class ApplicationOption
public IList FolderPermissions { get; set; } = new List();
+ public IList RegistrySettings { get; set; } = new List();
+
public IList FirewallRules { get; set; } = new List();
public IList ConfigurationSettingsFiles { get; set; } = new List();
diff --git a/src/Atc.Installer.Integration/InstallationConfigurations/RegistrySettingOption.cs b/src/Atc.Installer.Integration/InstallationConfigurations/RegistrySettingOption.cs
new file mode 100644
index 0000000..46f3da5
--- /dev/null
+++ b/src/Atc.Installer.Integration/InstallationConfigurations/RegistrySettingOption.cs
@@ -0,0 +1,11 @@
+namespace Atc.Installer.Integration.InstallationConfigurations;
+
+public class RegistrySettingOption
+{
+ public string Key { get; set; } = string.Empty;
+
+ public InsertRemoveType Action { get; set; }
+
+ public override string ToString()
+ => $"{nameof(Key)}: {Key}, {nameof(Action)}: {Action}";
+}
\ No newline at end of file
diff --git a/src/Atc.Installer.Wpf.App/Atc.Installer.Wpf.App.csproj b/src/Atc.Installer.Wpf.App/Atc.Installer.Wpf.App.csproj
index 975c35b..ac8d2f6 100644
--- a/src/Atc.Installer.Wpf.App/Atc.Installer.Wpf.App.csproj
+++ b/src/Atc.Installer.Wpf.App/Atc.Installer.Wpf.App.csproj
@@ -43,10 +43,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Atc.Installer.Wpf.App/Helpers/ConfigurationFileHelper.cs b/src/Atc.Installer.Wpf.App/Helpers/ConfigurationFileHelper.cs
index 932863a..9059e81 100644
--- a/src/Atc.Installer.Wpf.App/Helpers/ConfigurationFileHelper.cs
+++ b/src/Atc.Installer.Wpf.App/Helpers/ConfigurationFileHelper.cs
@@ -130,6 +130,15 @@ private static void MapCustomSettingsToTemplateSettings(
}
}
+ foreach (var customRegistrySetting in customApplication.RegistrySettings)
+ {
+ if (templateApplication.RegistrySettings.FirstOrDefault(x => x.Key == customRegistrySetting.Key) is
+ null)
+ {
+ templateApplication.RegistrySettings.Add(customRegistrySetting);
+ }
+ }
+
foreach (var customFirewallRule in customApplication.FirewallRules)
{
if (templateApplication.FirewallRules.FirstOrDefault(x => x.Name == customFirewallRule.Name) is null)
diff --git a/src/Atc.Installer.Wpf.App/MainWindowViewModel_Commands.cs b/src/Atc.Installer.Wpf.App/MainWindowViewModel_Commands.cs
index f7564c5..20122a8 100644
--- a/src/Atc.Installer.Wpf.App/MainWindowViewModel_Commands.cs
+++ b/src/Atc.Installer.Wpf.App/MainWindowViewModel_Commands.cs
@@ -118,6 +118,7 @@ InstallationFile is not null &&
x.DefaultApplicationSettings.IsDirty ||
x.ApplicationSettings.IsDirty ||
x.FolderPermissions.IsDirty ||
+ x.RegistrySettings.IsDirty ||
x.FirewallRules.IsDirty ||
x.ConfigurationSettingsFiles.IsDirty));
@@ -258,7 +259,7 @@ private async Task ReportingToExcelCommandHandler()
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal),
Title = "Select a file",
Filter = "Excel Files|*.xlsx",
- FileName = ProjectName,
+ FileName = ProjectName ?? "NoName",
};
if (saveFileDialog.ShowDialog() != true ||
diff --git a/src/Atc.Installer.Wpf.ComponentProvider.ElasticSearch/Atc.Installer.Wpf.ComponentProvider.ElasticSearch.csproj b/src/Atc.Installer.Wpf.ComponentProvider.ElasticSearch/Atc.Installer.Wpf.ComponentProvider.ElasticSearch.csproj
index dc78b85..cb8c1dd 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider.ElasticSearch/Atc.Installer.Wpf.ComponentProvider.ElasticSearch.csproj
+++ b/src/Atc.Installer.Wpf.ComponentProvider.ElasticSearch/Atc.Installer.Wpf.ComponentProvider.ElasticSearch.csproj
@@ -8,10 +8,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer.csproj b/src/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer.csproj
index a4fa938..eabfd41 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer.csproj
+++ b/src/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer.csproj
@@ -8,10 +8,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer/InternetInformationServerComponentProviderViewModel.cs b/src/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer/InternetInformationServerComponentProviderViewModel.cs
index cb3d659..6a06765 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer/InternetInformationServerComponentProviderViewModel.cs
+++ b/src/Atc.Installer.Wpf.ComponentProvider.InternetInformationServer/InternetInformationServerComponentProviderViewModel.cs
@@ -774,7 +774,7 @@ private void CheckPrerequisitesForHostingFramework()
{
switch (HostingFramework)
{
- case HostingFrameworkType.DonNetFramework48:
+ case HostingFrameworkType.DotNetFramework48:
if (iisInstallerService.IsMicrosoftDotNetFramework48())
{
AddToInstallationPrerequisites("IsMicrosoftDotNetFramework48", LogCategoryType.Information, "Microsoft .NET Framework 4.8 is installed");
@@ -976,6 +976,8 @@ private async Task ServiceDeployWebsitePostProcessing(
EnsureFolderPermissions();
+ EnsureRegistrySettings();
+
EnsureFirewallRules();
if (HostingFramework == HostingFrameworkType.NodeJs)
diff --git a/src/Atc.Installer.Wpf.ComponentProvider.PostgreSql/Atc.Installer.Wpf.ComponentProvider.PostgreSql.csproj b/src/Atc.Installer.Wpf.ComponentProvider.PostgreSql/Atc.Installer.Wpf.ComponentProvider.PostgreSql.csproj
index 6141700..8ecfc93 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider.PostgreSql/Atc.Installer.Wpf.ComponentProvider.PostgreSql.csproj
+++ b/src/Atc.Installer.Wpf.ComponentProvider.PostgreSql/Atc.Installer.Wpf.ComponentProvider.PostgreSql.csproj
@@ -8,10 +8,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Atc.Installer.Wpf.ComponentProvider.WindowsApplication/Atc.Installer.Wpf.ComponentProvider.WindowsApplication.csproj b/src/Atc.Installer.Wpf.ComponentProvider.WindowsApplication/Atc.Installer.Wpf.ComponentProvider.WindowsApplication.csproj
index 35ab153..a4028ec 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider.WindowsApplication/Atc.Installer.Wpf.ComponentProvider.WindowsApplication.csproj
+++ b/src/Atc.Installer.Wpf.ComponentProvider.WindowsApplication/Atc.Installer.Wpf.ComponentProvider.WindowsApplication.csproj
@@ -8,10 +8,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Atc.Installer.Wpf.ComponentProvider.WindowsApplication/WindowsApplicationComponentProviderViewModel.cs b/src/Atc.Installer.Wpf.ComponentProvider.WindowsApplication/WindowsApplicationComponentProviderViewModel.cs
index fcf0ca7..2932f61 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider.WindowsApplication/WindowsApplicationComponentProviderViewModel.cs
+++ b/src/Atc.Installer.Wpf.ComponentProvider.WindowsApplication/WindowsApplicationComponentProviderViewModel.cs
@@ -529,10 +529,10 @@ private void CheckPrerequisitesForHostingFramework()
case HostingFrameworkType.DotNet8:
AddToInstallationPrerequisites("IsMicrosoftDotNet8", LogCategoryType.Warning, "Microsoft .NET 8 is not installed");
break;
- case HostingFrameworkType.DonNetFramework48 when waInstallerService.IsMicrosoftDotNetFramework48():
+ case HostingFrameworkType.DotNetFramework48 when waInstallerService.IsMicrosoftDotNetFramework48():
AddToInstallationPrerequisites("IsMicrosoftDotNetFramework48", LogCategoryType.Information, "Microsoft .NET Framework 4.8 is installed");
break;
- case HostingFrameworkType.DonNetFramework48:
+ case HostingFrameworkType.DotNetFramework48:
AddToInstallationPrerequisites("IsMicrosoftDotNetFramework48", LogCategoryType.Warning, "Microsoft .NET Framework 4.8 is not installed");
break;
case HostingFrameworkType.Native:
@@ -796,6 +796,8 @@ private async Task ServiceDeployWindowServicePostProcessing(
EnsureFolderPermissions();
+ EnsureRegistrySettings();
+
EnsureFirewallRules();
if (TryGetStringFromApplicationSettings("WebProtocol", out _))
@@ -886,6 +888,8 @@ private Task ServiceDeployWindowApplicationCreate(
EnsureFolderPermissions();
+ EnsureRegistrySettings();
+
EnsureFirewallRules();
InstallationState = ComponentInstallationState.Installed;
@@ -921,6 +925,8 @@ private bool ServiceDeployWindowApplicationUpdate(
EnsureFolderPermissions();
+ EnsureRegistrySettings();
+
EnsureFirewallRules();
InstallationState = ComponentInstallationState.Installed;
diff --git a/src/Atc.Installer.Wpf.ComponentProvider/Atc.Installer.Wpf.ComponentProvider.csproj b/src/Atc.Installer.Wpf.ComponentProvider/Atc.Installer.Wpf.ComponentProvider.csproj
index 0ccfb80..3424b0b 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider/Atc.Installer.Wpf.ComponentProvider.csproj
+++ b/src/Atc.Installer.Wpf.ComponentProvider/Atc.Installer.Wpf.ComponentProvider.csproj
@@ -16,10 +16,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Atc.Installer.Wpf.ComponentProvider/ComponentProviderViewModel.cs b/src/Atc.Installer.Wpf.ComponentProvider/ComponentProviderViewModel.cs
index 041220d..ef732b4 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider/ComponentProviderViewModel.cs
+++ b/src/Atc.Installer.Wpf.ComponentProvider/ComponentProviderViewModel.cs
@@ -36,6 +36,7 @@ public ComponentProviderViewModel()
DefaultApplicationSettings = new ApplicationSettingsViewModel(isDefaultApplicationSettings: true, RefComponentProviders);
ApplicationSettings = new ApplicationSettingsViewModel(isDefaultApplicationSettings: false, RefComponentProviders);
FolderPermissions = new FolderPermissionsViewModel();
+ RegistrySettings = new RegistrySettingsViewModel();
FirewallRules = new FirewallRulesViewModel();
ConfigurationSettingsFiles = new ConfigurationSettingsFilesViewModel();
}
@@ -80,6 +81,9 @@ public ComponentProviderViewModel(
FolderPermissions = new FolderPermissionsViewModel();
FolderPermissions.Populate(this, applicationOption.FolderPermissions);
+ RegistrySettings = new RegistrySettingsViewModel();
+ RegistrySettings.Populate(this, applicationOption.RegistrySettings);
+
FirewallRules = new FirewallRulesViewModel();
FirewallRules.Populate(this, applicationOption.FirewallRules);
@@ -155,6 +159,8 @@ public bool ShowOnlyBaseSettings
public FolderPermissionsViewModel FolderPermissions { get; }
+ public RegistrySettingsViewModel RegistrySettings { get; }
+
public FirewallRulesViewModel FirewallRules { get; }
public ConfigurationSettingsFilesViewModel ConfigurationSettingsFiles { get; }
diff --git a/src/Atc.Installer.Wpf.ComponentProvider/ComponentProviderViewModel_LogicBase.cs b/src/Atc.Installer.Wpf.ComponentProvider/ComponentProviderViewModel_LogicBase.cs
index 8e2cd8f..ec57cd5 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider/ComponentProviderViewModel_LogicBase.cs
+++ b/src/Atc.Installer.Wpf.ComponentProvider/ComponentProviderViewModel_LogicBase.cs
@@ -3,6 +3,7 @@
// ReSharper disable ReturnTypeCanBeEnumerable.Local
// ReSharper disable StringLiteralTypo
// ReSharper disable SwitchStatementHandlesSomeKnownEnumValuesWithDefault
+// ReSharper disable SwitchStatementMissingSomeEnumCasesNoDefault
namespace Atc.Installer.Wpf.ComponentProvider;
[SuppressMessage("Design", "MA0048:File name must match type name", Justification = "OK - partial class")]
@@ -110,7 +111,7 @@ public void LoadConfigurationFiles()
switch (HostingFramework)
{
- case HostingFrameworkType.DonNetFramework48:
+ case HostingFrameworkType.DotNetFramework48:
{
if (InstalledMainFilePath is not null)
{
@@ -201,10 +202,21 @@ public void PrepareInstallationFiles(
UnpackedZipFolderPath = Path.Combine(InstallerTempDirectory.FullName, @$"{ProjectName}\Unpacked\{Name}");
- if (Directory.Exists(UnpackedZipFolderPath) &&
- Directory.GetFiles(UnpackedZipFolderPath).Length == 0)
+ if (Directory.Exists(UnpackedZipFolderPath))
{
- Directory.Delete(UnpackedZipFolderPath, recursive: true);
+ var minimumExpectedNumberOfFiles = 1;
+ if (HostingFramework is
+ HostingFrameworkType.DotNetFramework48 or
+ HostingFrameworkType.DotNet7 or
+ HostingFrameworkType.DotNet8)
+ {
+ minimumExpectedNumberOfFiles = 10;
+ }
+
+ if (Directory.GetFiles(UnpackedZipFolderPath).Length < minimumExpectedNumberOfFiles)
+ {
+ Directory.Delete(UnpackedZipFolderPath, recursive: true);
+ }
}
if (unpackIfExist ||
@@ -524,6 +536,69 @@ protected void EnsureFolderPermissions()
AddLogItem(LogLevel.Information, "Folder permissions is ensured");
}
+ protected void EnsureRegistrySettings()
+ {
+ AddLogItem(LogLevel.Trace, "Ensure registry settings");
+
+ foreach (var vm in RegistrySettings.Items)
+ {
+ var key = vm.Key;
+ if (key.ContainsTemplatePattern())
+ {
+ key = ResolveTemplateIfNeededByApplicationSettingsLookup(key);
+ }
+
+ if (key.StartsWith("HKEY_LOCAL_MACHINE\\", StringComparison.Ordinal))
+ {
+ key = key.Replace("HKEY_LOCAL_MACHINE\\", string.Empty, StringComparison.Ordinal);
+ switch (vm.Action)
+ {
+ case InsertRemoveType.Insert:
+ var insertResult = RegistryHelper.CreateSubKeyInLocalMachine(key);
+ if (!insertResult.IsSucceeded)
+ {
+ AddLogItem(LogLevel.Error, insertResult.ErrorMessage!);
+ }
+
+ break;
+ case InsertRemoveType.Remove:
+ var removeResult = RegistryHelper.DeleteSubKeyTreeInLocalMachine(key);
+ if (!removeResult.IsSucceeded)
+ {
+ AddLogItem(LogLevel.Error, removeResult.ErrorMessage!);
+ }
+
+ break;
+ }
+ }
+ else if (key.StartsWith("HKEY_CURRENT_USER\\", StringComparison.Ordinal))
+ {
+ key = key.Replace("HKEY_CURRENT_USER\\", string.Empty, StringComparison.Ordinal);
+ switch (vm.Action)
+ {
+ case InsertRemoveType.Insert:
+ var insertResult = RegistryHelper.CreateSubKeyInCurrentUser(key);
+ if (!insertResult.IsSucceeded)
+ {
+ AddLogItem(LogLevel.Error, insertResult.ErrorMessage!);
+ }
+
+ break;
+ case InsertRemoveType.Remove:
+ var removeResult = RegistryHelper.DeleteSubKeyTreeInCurrentUser(key);
+ if (!removeResult.IsSucceeded)
+ {
+ AddLogItem(LogLevel.Error, removeResult.ErrorMessage!);
+ }
+
+ break;
+ }
+ }
+ }
+
+ AddLogItem(LogLevel.Trace, "Registry settings is ensured");
+ }
+
protected void EnsureFirewallRules()
{
AddLogItem(LogLevel.Trace, "Ensure firewall rules");
@@ -760,7 +835,7 @@ public async Task GetReportingData()
switch (HostingFramework)
{
- case HostingFrameworkType.DonNetFramework48 or
+ case HostingFrameworkType.DotNetFramework48 or
HostingFrameworkType.DotNet7 or
HostingFrameworkType.DotNet8:
{
@@ -883,7 +958,7 @@ private void ResolveInstalledMainFile(
{
case { ComponentType: ComponentType.Application, HostingFramework: HostingFrameworkType.DotNet7 }:
case { ComponentType: ComponentType.Application, HostingFramework: HostingFrameworkType.DotNet8 }:
- case { ComponentType: ComponentType.Application, HostingFramework: HostingFrameworkType.DonNetFramework48 }:
+ case { ComponentType: ComponentType.Application, HostingFramework: HostingFrameworkType.DotNetFramework48 }:
InstalledMainFilePath = new ValueTemplateItemViewModel(
Path.Combine(basePath, $"{Name}.exe"),
template: instFolderPath,
@@ -897,7 +972,7 @@ private void ResolveInstalledMainFile(
break;
case { ComponentType: ComponentType.InternetInformationService, HostingFramework: HostingFrameworkType.DotNet7 }:
case { ComponentType: ComponentType.InternetInformationService, HostingFramework: HostingFrameworkType.DotNet8 }:
- case { ComponentType: ComponentType.InternetInformationService, HostingFramework: HostingFrameworkType.DonNetFramework48 }:
+ case { ComponentType: ComponentType.InternetInformationService, HostingFramework: HostingFrameworkType.DotNetFramework48 }:
InstalledMainFilePath = new ValueTemplateItemViewModel(
Path.Combine(basePath, $"{Name}.dll"),
template: instFolderPath,
@@ -911,7 +986,7 @@ private void ResolveInstalledMainFile(
break;
case { ComponentType: ComponentType.WindowsService, HostingFramework: HostingFrameworkType.DotNet7 }:
case { ComponentType: ComponentType.WindowsService, HostingFramework: HostingFrameworkType.DotNet8 }:
- case { ComponentType: ComponentType.WindowsService, HostingFramework: HostingFrameworkType.DonNetFramework48 }:
+ case { ComponentType: ComponentType.WindowsService, HostingFramework: HostingFrameworkType.DotNetFramework48 }:
InstalledMainFilePath = new ValueTemplateItemViewModel(
Path.Combine(basePath, $"{Name}.exe"),
template: instFolderPath,
diff --git a/src/Atc.Installer.Wpf.ComponentProvider/Controls/RegistrySettingsViewModel.cs b/src/Atc.Installer.Wpf.ComponentProvider/Controls/RegistrySettingsViewModel.cs
new file mode 100644
index 0000000..f6d7cde
--- /dev/null
+++ b/src/Atc.Installer.Wpf.ComponentProvider/Controls/RegistrySettingsViewModel.cs
@@ -0,0 +1,61 @@
+namespace Atc.Installer.Wpf.ComponentProvider.Controls;
+
+public class RegistrySettingsViewModel : ViewModelBase
+{
+ private ComponentProviderViewModel? refComponentProvider;
+ private bool enableEditingMode;
+
+ public RegistrySettingsViewModel()
+ => Messenger.Default.Register(this, HandleUpdateApplicationOptionsMessage);
+
+ public bool EnableEditingMode
+ {
+ get => enableEditingMode;
+ set
+ {
+ if (enableEditingMode == value)
+ {
+ return;
+ }
+
+ enableEditingMode = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public ObservableCollectionEx Items { get; init; } = new();
+
+ public void Populate(
+ ComponentProviderViewModel refComponentProviderViewModel,
+ IList registrySettings)
+ {
+ ArgumentNullException.ThrowIfNull(refComponentProviderViewModel);
+ ArgumentNullException.ThrowIfNull(registrySettings);
+
+ refComponentProvider = refComponentProviderViewModel;
+
+ Items.Clear();
+
+ Items.SuppressOnChangedNotification = true;
+
+ foreach (var registrySetting in registrySettings)
+ {
+ Items.Add(new RegistrySettingViewModel(registrySetting));
+ }
+
+ Items.SuppressOnChangedNotification = false;
+ }
+
+ public void ClearAllIsDirty()
+ {
+ IsDirty = false;
+ foreach (var item in Items)
+ {
+ item.IsDirty = false;
+ }
+ }
+
+ private void HandleUpdateApplicationOptionsMessage(
+ UpdateApplicationOptionsMessage obj)
+ => EnableEditingMode = obj.EnableEditingMode;
+}
\ No newline at end of file
diff --git a/src/Atc.Installer.Wpf.ComponentProvider/ValueConverters/ComponentProviderVersionCompareVisibilityVisibleValueConverter.cs b/src/Atc.Installer.Wpf.ComponentProvider/ValueConverters/ComponentProviderVersionCompareVisibilityVisibleValueConverter.cs
index f08a1cc..c86dd38 100644
--- a/src/Atc.Installer.Wpf.ComponentProvider/ValueConverters/ComponentProviderVersionCompareVisibilityVisibleValueConverter.cs
+++ b/src/Atc.Installer.Wpf.ComponentProvider/ValueConverters/ComponentProviderVersionCompareVisibilityVisibleValueConverter.cs
@@ -21,7 +21,7 @@ public object Convert(
}
if (vm.HostingFramework is
- HostingFrameworkType.DonNetFramework48 or
+ HostingFrameworkType.DotNetFramework48 or
HostingFrameworkType.DotNet7 or
HostingFrameworkType.DotNet8)
{
diff --git a/src/Atc.Installer.Wpf.ComponentProvider/ViewModels/RegistrySettingViewModel.cs b/src/Atc.Installer.Wpf.ComponentProvider/ViewModels/RegistrySettingViewModel.cs
new file mode 100644
index 0000000..61ebb7d
--- /dev/null
+++ b/src/Atc.Installer.Wpf.ComponentProvider/ViewModels/RegistrySettingViewModel.cs
@@ -0,0 +1,43 @@
+namespace Atc.Installer.Wpf.ComponentProvider.ViewModels;
+
+public class RegistrySettingViewModel : ViewModelBase
+{
+ private string key = string.Empty;
+ private InsertRemoveType action;
+
+ public RegistrySettingViewModel()
+ {
+ }
+
+ public RegistrySettingViewModel(
+ RegistrySettingOption registrySetting)
+ {
+ ArgumentNullException.ThrowIfNull(registrySetting);
+
+ Key = registrySetting.Key;
+ Action = registrySetting.Action;
+ }
+
+ public string Key
+ {
+ get => key;
+ set
+ {
+ key = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public InsertRemoveType Action
+ {
+ get => action;
+ set
+ {
+ action = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public override string ToString()
+ => $"{nameof(Key)}: {Key}, {nameof(Action)}: {Action}";
+}
\ No newline at end of file