aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-11 12:23:19 -0700
committerRob Mensching <rob@firegiant.com>2021-04-12 19:28:07 -0700
commitae7e9817bb10d635e031e51496f2e529595a9cfe (patch)
treec70942b721dc860dd8ea7d14e90ed0f880030983 /src
parent13c4becf524dbd12b92f099320726aa0b59f3bbc (diff)
downloadwix-ae7e9817bb10d635e031e51496f2e529595a9cfe.tar.gz
wix-ae7e9817bb10d635e031e51496f2e529595a9cfe.tar.bz2
wix-ae7e9817bb10d635e031e51496f2e529595a9cfe.zip
Add RemoveRegistryKey
Diffstat (limited to 'src')
-rw-r--r--src/ca/RemoveRegistryKeysEx.cpp114
-rw-r--r--src/ca/utilca.def2
-rw-r--r--src/ca/utilca.vcxproj1
-rw-r--r--src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs13
-rw-r--r--src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs10
-rw-r--r--src/test/WixToolsetTest.Util/UtilExtensionFixture.cs15
-rw-r--r--src/wixext/Symbols/UtilSymbolDefinitions.cs4
-rw-r--r--src/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs86
-rw-r--r--src/wixext/UtilCompiler.cs103
-rw-r--r--src/wixext/UtilTableDefinitions.cs16
-rw-r--r--src/wixlib/UtilExtension_Platform.wxi8
11 files changed, 366 insertions, 6 deletions
diff --git a/src/ca/RemoveRegistryKeysEx.cpp b/src/ca/RemoveRegistryKeysEx.cpp
new file mode 100644
index 00000000..478c0779
--- /dev/null
+++ b/src/ca/RemoveRegistryKeysEx.cpp
@@ -0,0 +1,114 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5LPCWSTR vcsRemoveRegistryKeyExQuery =
6 L"SELECT `Wix4RemoveRegistryKeyEx`, `Component_`, `Root`, `Key`, `InstallMode`, `Condition` FROM `Wix4RemoveRegistryKeyEx`";
7enum eRemoveRegistryKeyExQuery { rrxqId = 1, rrxqComponent, rrxqRoot, rrxqKey, rrxqMode, rrxqCondition };
8
9extern "C" UINT WINAPI WixRemoveRegistryKeysEx(
10 __in MSIHANDLE hInstall
11)
12{
13 //AssertSz(FALSE, "debug WixRemoveRegistryKeyEx");
14
15 HRESULT hr = S_OK;
16 PMSIHANDLE hView;
17 PMSIHANDLE hRec;
18 LPWSTR sczId = NULL;
19 LPWSTR sczComponent = NULL;
20 LPWSTR sczCondition = NULL;
21 LPWSTR sczKey = NULL;
22 int iRoot = 0;
23 int iMode = 0;
24 MSIHANDLE hTable = NULL;
25 MSIHANDLE hColumns = NULL;
26
27 hr = WcaInitialize(hInstall, __FUNCTION__);
28 ExitOnFailure(hr, "Failed to initialize " __FUNCTION__);
29
30 // anything to do?
31 if (S_OK != WcaTableExists(L"Wix4RemoveRegistryKeyEx"))
32 {
33 WcaLog(LOGMSG_STANDARD, "Wix4RemoveRegistryKeyEx table doesn't exist, so there are no registry keys to remove.");
34 ExitFunction();
35 }
36
37 hr = WcaOpenExecuteView(vcsRemoveRegistryKeyExQuery, &hView);
38 ExitOnFailure(hr, "Failed to open view on Wix4RemoveRegistryKeyEx table");
39
40 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
41 {
42 hr = WcaGetRecordString(hRec, rrxqId, &sczId);
43 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx identity.");
44
45 hr = WcaGetRecordString(hRec, rrxqCondition, &sczCondition);
46 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx condition.");
47
48 if (sczCondition && *sczCondition)
49 {
50 MSICONDITION condition = ::MsiEvaluateConditionW(hInstall, sczCondition);
51 if (MSICONDITION_TRUE == condition)
52 {
53 WcaLog(LOGMSG_STANDARD, "True condition for row %S: %S; processing.", sczId, sczCondition);
54 }
55 else
56 {
57 WcaLog(LOGMSG_STANDARD, "False or invalid condition for row %S: %S; skipping.", sczId, sczCondition);
58 continue;
59 }
60 }
61
62 hr = WcaGetRecordString(hRec, rrxqComponent, &sczComponent);
63 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx component.");
64
65 hr = WcaGetRecordInteger(hRec, rrxqRoot, &iRoot);
66 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx root.");
67
68 hr = WcaGetRecordString(hRec, rrxqKey, &sczKey);
69 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx key.");
70
71 hr = WcaGetRecordInteger(hRec, rrxqMode, &iMode);
72 ExitOnFailure(hr, "Failed to get Wix4RemoveRegistryKeyEx mode.");
73
74 switch (iMode)
75 {
76 case 1: // remove on install
77 WcaLog(LOGMSG_STANDARD, "Adding RemoveRegistry row: %ls/%d/%ls/-/%ls", sczId, iRoot, sczKey, sczComponent);
78 hr = WcaAddTempRecord(&hTable, &hColumns, L"RemoveRegistry", NULL, 0, 5, sczId, iRoot, sczKey, L"-", sczComponent);
79 ExitOnFailure(hr, "Failed to add RemoveRegistry row for remove-on-install Wix4RemoveRegistryKeyEx row: %ls:", sczId);
80 break;
81 case 2: // remove on uninstall
82 WcaLog(LOGMSG_STANDARD, "Adding Registry row: %ls/%d/%ls/-/null/%ls", sczId, iRoot, sczKey, sczComponent);
83 hr = WcaAddTempRecord(&hTable, &hColumns, L"Registry", NULL, 0, 6, sczId, iRoot, sczKey, L"-", NULL, sczComponent);
84 ExitOnFailure(hr, "Failed to add Registry row for remove-on-uninstall Wix4RemoveRegistryKeyEx row: %ls:", sczId);
85 break;
86 }
87 }
88
89 // reaching the end of the list is actually a good thing, not an error
90 if (E_NOMOREITEMS == hr)
91 {
92 hr = S_OK;
93 }
94 ExitOnFailure(hr, "Failure occured while processing Wix4RemoveRegistryKeyEx table.");
95
96LExit:
97 if (hColumns)
98 {
99 ::MsiCloseHandle(hColumns);
100 }
101
102 if (hTable)
103 {
104 ::MsiCloseHandle(hTable);
105 }
106
107 ReleaseStr(sczKey);
108 ReleaseStr(sczComponent);
109 ReleaseStr(sczCondition);
110 ReleaseStr(sczId);
111
112 DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
113 return WcaFinalize(er);
114}
diff --git a/src/ca/utilca.def b/src/ca/utilca.def
index 97d5776f..337c3a68 100644
--- a/src/ca/utilca.def
+++ b/src/ca/utilca.def
@@ -35,6 +35,8 @@ EXPORTS
35 WixSilentExec64 35 WixSilentExec64
36; RemoveFoldersEx.cpp 36; RemoveFoldersEx.cpp
37 WixRemoveFoldersEx 37 WixRemoveFoldersEx
38; RemoveRegistryKeysEx.cpp
39 WixRemoveRegistryKeysEx
38;scaexec.cpp 40;scaexec.cpp
39 RegisterPerfCounterData 41 RegisterPerfCounterData
40 UnregisterPerfCounterData 42 UnregisterPerfCounterData
diff --git a/src/ca/utilca.vcxproj b/src/ca/utilca.vcxproj
index 4fafba68..6a076f2f 100644
--- a/src/ca/utilca.vcxproj
+++ b/src/ca/utilca.vcxproj
@@ -59,6 +59,7 @@
59 <ClCompile Include="OsInfo.cpp" /> 59 <ClCompile Include="OsInfo.cpp" />
60 <ClCompile Include="qtexecca.cpp" /> 60 <ClCompile Include="qtexecca.cpp" />
61 <ClCompile Include="RemoveFoldersEx.cpp" /> 61 <ClCompile Include="RemoveFoldersEx.cpp" />
62 <ClCompile Include="RemoveRegistryKeysEx.cpp" />
62 <ClCompile Include="RestartManager.cpp" /> 63 <ClCompile Include="RestartManager.cpp" />
63 <ClCompile Include="scaexec.cpp" /> 64 <ClCompile Include="scaexec.cpp" />
64 <ClCompile Include="scamanifest.cpp" /> 65 <ClCompile Include="scamanifest.cpp" />
diff --git a/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs b/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs
new file mode 100644
index 00000000..32b246f4
--- /dev/null
+++ b/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/Module.wxs
@@ -0,0 +1,13 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Module Language="1033" Version="1.0.0.0" Id="InternetShortcutModule" Guid="047730a5-30fe-4a62-a520-da9381b8226a">
3 <SummaryInformation Manufacturer="Example Corporation" />
4
5 <ComponentGroupRef Id="ModuleComponents" />
6 </Module>
7
8 <Fragment>
9 <StandardDirectory Id="ProgramFilesFolder">
10 <Directory Id="INSTALLFOLDER" Name="MergeModule" />
11 </StandardDirectory>
12 </Fragment>
13</Wix>
diff --git a/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs b/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs
new file mode 100644
index 00000000..0a0c8cb6
--- /dev/null
+++ b/src/test/WixToolsetTest.Util/TestData/RemoveRegistryKeyEx/ModuleComponents.wxs
@@ -0,0 +1,10 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2 <Fragment>
3 <ComponentGroup Id="ModuleComponents" Directory="INSTALLFOLDER">
4 <Component>
5 <File Source="ModuleComponents.wxs" />
6 <util:RemoveRegistryKey Root="HKLM" Key="SOFTWARE\Example" On="install" />
7 </Component>
8 </ComponentGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs b/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs
index 9c32ebc2..883f9794 100644
--- a/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs
+++ b/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs
@@ -130,6 +130,21 @@ namespace WixToolsetTest.Util
130 } 130 }
131 131
132 [Fact] 132 [Fact]
133 public void CanBuildRemoveRegistryKeyExInMergeModule()
134 {
135 var folder = TestData.Get(@"TestData", "RemoveRegistryKeyEx");
136 var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }, "test.msm");
137
138 var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "RemoveRegistry", "Wix4RemoveRegistryKeyEx");
139 WixAssert.CompareLineByLine(new[]
140 {
141 "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]",
142 "CustomAction:Wix4RemoveRegistryKeysEx_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t65\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRemoveRegistryKeysEx\t",
143 "Wix4RemoveRegistryKeyEx:rrxfcDhR4HhE3v3rYiQcNtQjyahQNg.047730A5_30FE_4A62_A520_DA9381B8226A\tfilh4juyUVjoUcWWtcQmd5L07FoON4.047730A5_30FE_4A62_A520_DA9381B8226A\t2\tSOFTWARE\\Example\t1\t",
144 }, results.OrderBy(s => s).ToArray());
145 }
146
147 [Fact]
133 public void CanBuildRemoveFolderExInMergeModule() 148 public void CanBuildRemoveFolderExInMergeModule()
134 { 149 {
135 var folder = TestData.Get(@"TestData\RemoveFolderEx"); 150 var folder = TestData.Get(@"TestData\RemoveFolderEx");
diff --git a/src/wixext/Symbols/UtilSymbolDefinitions.cs b/src/wixext/Symbols/UtilSymbolDefinitions.cs
index 5f062676..72091c3b 100644
--- a/src/wixext/Symbols/UtilSymbolDefinitions.cs
+++ b/src/wixext/Symbols/UtilSymbolDefinitions.cs
@@ -23,6 +23,7 @@ namespace WixToolset.Util
23 WixFormatFiles, 23 WixFormatFiles,
24 WixInternetShortcut, 24 WixInternetShortcut,
25 WixRemoveFolderEx, 25 WixRemoveFolderEx,
26 WixRemoveRegistryKeyEx,
26 WixRestartResource, 27 WixRestartResource,
27 WixTouchFile, 28 WixTouchFile,
28 WixWindowsFeatureSearch, 29 WixWindowsFeatureSearch,
@@ -93,6 +94,9 @@ namespace WixToolset.Util
93 case UtilSymbolDefinitionType.WixRemoveFolderEx: 94 case UtilSymbolDefinitionType.WixRemoveFolderEx:
94 return UtilSymbolDefinitions.WixRemoveFolderEx; 95 return UtilSymbolDefinitions.WixRemoveFolderEx;
95 96
97 case UtilSymbolDefinitionType.WixRemoveRegistryKeyEx:
98 return UtilSymbolDefinitions.WixRemoveRegistryKeyEx;
99
96 case UtilSymbolDefinitionType.WixRestartResource: 100 case UtilSymbolDefinitionType.WixRestartResource:
97 return UtilSymbolDefinitions.WixRestartResource; 101 return UtilSymbolDefinitions.WixRestartResource;
98 102
diff --git a/src/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs b/src/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs
new file mode 100644
index 00000000..8e4bd212
--- /dev/null
+++ b/src/wixext/Symbols/WixRemoveRegistryKeyExSymbol.cs
@@ -0,0 +1,86 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Util
4{
5 using WixToolset.Data;
6 using WixToolset.Util.Symbols;
7
8 public static partial class UtilSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixRemoveRegistryKeyEx = new IntermediateSymbolDefinition(
11 UtilSymbolDefinitionType.WixRemoveRegistryKeyEx.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Root), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Key), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.InstallMode), IntermediateFieldType.Number),
18 new IntermediateFieldDefinition(nameof(WixRemoveRegistryKeyExSymbolFields.Condition), IntermediateFieldType.String),
19 },
20 typeof(WixRemoveRegistryKeyExSymbol));
21 }
22}
23
24namespace WixToolset.Util.Symbols
25{
26 using WixToolset.Data;
27 using WixToolset.Data.Symbols;
28
29 public enum WixRemoveRegistryKeyExSymbolFields
30 {
31 ComponentRef,
32 Root,
33 Key,
34 InstallMode,
35 Condition,
36 }
37
38 public enum WixRemoveRegistryKeyExInstallMode
39 {
40 Install = 1,
41 Uninstall = 2,
42 }
43
44 public class WixRemoveRegistryKeyExSymbol : IntermediateSymbol
45 {
46 public WixRemoveRegistryKeyExSymbol() : base(UtilSymbolDefinitions.WixRemoveRegistryKeyEx, null, null)
47 {
48 }
49
50 public WixRemoveRegistryKeyExSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.WixRemoveRegistryKeyEx, sourceLineNumber, id)
51 {
52 }
53
54 public IntermediateField this[WixRemoveRegistryKeyExSymbolFields index] => this.Fields[(int)index];
55
56 public string ComponentRef
57 {
58 get => this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.ComponentRef].AsString();
59 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.ComponentRef, value);
60 }
61
62 public RegistryRootType Root
63 {
64 get => (RegistryRootType)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Root].AsNumber();
65 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Root, (int)value);
66 }
67
68 public string Key
69 {
70 get => (string)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Key];
71 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Key, value);
72 }
73
74 public WixRemoveRegistryKeyExInstallMode InstallMode
75 {
76 get => (WixRemoveRegistryKeyExInstallMode)this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.InstallMode].AsNumber();
77 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.InstallMode, (int)value);
78 }
79
80 public string Condition
81 {
82 get => this.Fields[(int)WixRemoveRegistryKeyExSymbolFields.Condition].AsString();
83 set => this.Set((int)WixRemoveRegistryKeyExSymbolFields.Condition, value);
84 }
85 }
86}
diff --git a/src/wixext/UtilCompiler.cs b/src/wixext/UtilCompiler.cs
index 63f2b469..45079150 100644
--- a/src/wixext/UtilCompiler.cs
+++ b/src/wixext/UtilCompiler.cs
@@ -35,12 +35,6 @@ namespace WixToolset.Util
35 internal const int UserDontCreateUser = 0x00000200; 35 internal const int UserDontCreateUser = 0x00000200;
36 internal const int UserNonVital = 0x00000400; 36 internal const int UserNonVital = 0x00000400;
37 37
38 internal enum WixRegistrySearchFormat
39 {
40 Raw,
41 Compatible,
42 }
43
44 private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled); 38 private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled);
45 39
46 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/util"; 40 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/util";
@@ -135,6 +129,9 @@ namespace WixToolset.Util
135 case "RemoveFolderEx": 129 case "RemoveFolderEx":
136 this.ParseRemoveFolderExElement(intermediate, section, element, componentId); 130 this.ParseRemoveFolderExElement(intermediate, section, element, componentId);
137 break; 131 break;
132 case "RemoveRegistryKey":
133 this.ParseRemoveRegistryKeyExElement(intermediate, section, element, componentId);
134 break;
138 case "RestartResource": 135 case "RestartResource":
139 this.ParseRestartResourceElement(intermediate, section, element, componentId); 136 this.ParseRestartResourceElement(intermediate, section, element, componentId);
140 break; 137 break;
@@ -2888,6 +2885,100 @@ namespace WixToolset.Util
2888 } 2885 }
2889 2886
2890 /// <summary> 2887 /// <summary>
2888 /// Parses a RemoveRegistryKeyEx element.
2889 /// </summary>
2890 /// <param name="node">Element to parse.</param>
2891 /// <param name="componentId">Identifier of parent component.</param>
2892 private void ParseRemoveRegistryKeyExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2893 {
2894 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2895 Identifier id = null;
2896 var mode = WixRemoveRegistryKeyExInstallMode.Uninstall;
2897 string condition = null;
2898 RegistryRootType? root = null;
2899 string key = null;
2900
2901 foreach (var attrib in element.Attributes())
2902 {
2903 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2904 {
2905 switch (attrib.Name.LocalName)
2906 {
2907 case "Condition":
2908 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2909 break;
2910 case "Id":
2911 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2912 break;
2913 case "On":
2914 var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2915 switch (actionValue)
2916 {
2917 case "":
2918 break;
2919 case "install":
2920 mode = WixRemoveRegistryKeyExInstallMode.Install;
2921 break;
2922 case "uninstall":
2923 mode = WixRemoveRegistryKeyExInstallMode.Uninstall;
2924 break;
2925 default:
2926 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", actionValue, "install", "uninstall"));
2927 break;
2928 }
2929 break;
2930 case "Root":
2931 root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false);
2932 break;
2933 case "Key":
2934 key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2935 break;
2936 default:
2937 this.ParseHelper.UnexpectedAttribute(element, attrib);
2938 break;
2939 }
2940 }
2941 else
2942 {
2943 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2944 }
2945 }
2946
2947 if (!root.HasValue)
2948 {
2949 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
2950 }
2951
2952 if (key == null)
2953 {
2954 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key"));
2955 }
2956
2957 if (id == null)
2958 {
2959 id = this.ParseHelper.CreateIdentifier("rrx", componentId, condition, root.ToString(), key, mode.ToString());
2960 }
2961
2962 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2963
2964 if (!this.Messaging.EncounteredError)
2965 {
2966 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "Registry");
2967 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveRegistry");
2968 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveRegistryKeysEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2969
2970 section.AddSymbol(new WixRemoveRegistryKeyExSymbol(sourceLineNumbers, id)
2971 {
2972 ComponentRef = componentId,
2973 Root = root.Value,
2974 Key = key,
2975 InstallMode = mode,
2976 Condition = condition
2977 });
2978 }
2979 }
2980
2981 /// <summary>
2891 /// Parses a RestartResource element. 2982 /// Parses a RestartResource element.
2892 /// </summary> 2983 /// </summary>
2893 /// <param name="element">The element to parse.</param> 2984 /// <param name="element">The element to parse.</param>
diff --git a/src/wixext/UtilTableDefinitions.cs b/src/wixext/UtilTableDefinitions.cs
index fd09367a..12f423cc 100644
--- a/src/wixext/UtilTableDefinitions.cs
+++ b/src/wixext/UtilTableDefinitions.cs
@@ -38,6 +38,21 @@ namespace WixToolset.Util
38 symbolIdIsPrimaryKey: true 38 symbolIdIsPrimaryKey: true
39 ); 39 );
40 40
41 public static readonly TableDefinition Wix4RemoveRegistryKeyEx = new TableDefinition(
42 "Wix4RemoveRegistryKeyEx",
43 UtilSymbolDefinitions.WixRemoveRegistryKeyEx,
44 new[]
45 {
46 new ColumnDefinition("Wix4RemoveRegistryKeyEx", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Identifier for the Wix4RemoveRegistryKeyEx row in the package.", modularizeType: ColumnModularizeType.Column),
47 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table used to determine install state", modularizeType: ColumnModularizeType.Column),
48 new ColumnDefinition("Root", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: -1, maxValue: 3, description: "The predefined root key for the registry value, one of rrkEnum."),
49 new ColumnDefinition("Key", ColumnType.Localized, 255, primaryKey: false, nullable: false, ColumnCategory.RegPath, description: "The key for the registry value.", modularizeType: ColumnModularizeType.Property),
50 new ColumnDefinition("InstallMode", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 1, maxValue: 3, description: "1 == Remove only when the associated component is being installed (msiInstallStateLocal or msiInstallStateSource), 2 == Remove only when the associated component is being removed (msiInstallStateAbsent), 3 = Remove in either of the above cases."),
51 new ColumnDefinition("Condition", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Condition, description: "Optional expression to control whether the registry key is removed.", modularizeType: ColumnModularizeType.Condition, forceLocalizable: true),
52 },
53 symbolIdIsPrimaryKey: true
54 );
55
41 public static readonly TableDefinition Wix4RestartResource = new TableDefinition( 56 public static readonly TableDefinition Wix4RestartResource = new TableDefinition(
42 "Wix4RestartResource", 57 "Wix4RestartResource",
43 UtilSymbolDefinitions.WixRestartResource, 58 UtilSymbolDefinitions.WixRestartResource,
@@ -281,6 +296,7 @@ namespace WixToolset.Util
281 { 296 {
282 Wix4CloseApplication, 297 Wix4CloseApplication,
283 Wix4RemoveFolderEx, 298 Wix4RemoveFolderEx,
299 Wix4RemoveRegistryKeyEx,
284 Wix4RestartResource, 300 Wix4RestartResource,
285 Wix4FileShare, 301 Wix4FileShare,
286 Wix4FileSharePermissions, 302 Wix4FileSharePermissions,
diff --git a/src/wixlib/UtilExtension_Platform.wxi b/src/wixlib/UtilExtension_Platform.wxi
index 974169ff..d88b2a57 100644
--- a/src/wixlib/UtilExtension_Platform.wxi
+++ b/src/wixlib/UtilExtension_Platform.wxi
@@ -45,6 +45,14 @@
45 </Fragment> 45 </Fragment>
46 46
47 <Fragment> 47 <Fragment>
48 <CustomAction Id="$(var.Prefix)RemoveRegistryKeysEx$(var.Suffix)" DllEntry="WixRemoveRegistryKeysEx" Execute="immediate" Return="ignore" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
49
50 <InstallExecuteSequence>
51 <Custom Action="$(var.Prefix)RemoveRegistryKeysEx$(var.Suffix)" Before="RemoveRegistryValues" />
52 </InstallExecuteSequence>
53 </Fragment>
54
55 <Fragment>
48 <CustomAction Id="$(var.Prefix)BroadcastSettingChange$(var.Suffix)" DllEntry="WixBroadcastSettingChange" Execute="immediate" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> 56 <CustomAction Id="$(var.Prefix)BroadcastSettingChange$(var.Suffix)" DllEntry="WixBroadcastSettingChange" Execute="immediate" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
49 57
50 <InstallExecuteSequence> 58 <InstallExecuteSequence>