aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ca/RemoveFoldersEx.cpp62
-rw-r--r--src/test/WixToolsetTest.Util/UtilExtensionFixture.cs4
-rw-r--r--src/wixext/Symbols/WixRemoveFolderExSymbol.cs21
-rw-r--r--src/wixext/UtilCompiler.cs28
-rw-r--r--src/wixext/UtilTableDefinitions.cs1
5 files changed, 87 insertions, 29 deletions
diff --git a/src/ca/RemoveFoldersEx.cpp b/src/ca/RemoveFoldersEx.cpp
index ce64c2c2..cbc7f4bb 100644
--- a/src/ca/RemoveFoldersEx.cpp
+++ b/src/ca/RemoveFoldersEx.cpp
@@ -2,8 +2,11 @@
2 2
3#include "precomp.h" 3#include "precomp.h"
4 4
5LPCWSTR vcsRemoveFolderExQuery = L"SELECT `Wix4RemoveFolderEx`, `Component_`, `Property`, `InstallMode` FROM `Wix4RemoveFolderEx`"; 5LPCWSTR vcsRemoveFolderExQuery =
6enum eRemoveFolderExQuery { rfqId = 1, rfqComponent, rfqProperty, feqMode }; 6 L"SELECT `Wix4RemoveFolderEx`, `Component_`, `Property`, `InstallMode`, `WixRemoveFolderEx`.`Condition`, `Component`.`Attributes`"
7 L"FROM `Wix4RemoveFolderEx``,`Component` "
8 L"WHERE `Wix4RemoveFolderEx`.`Component_`=`Component`.`Component`";
9enum eRemoveFolderExQuery { rfqId = 1, rfqComponent, rfqProperty, rfqMode, rfqCondition, rfqComponentAttributes };
7 10
8static HRESULT RecursePath( 11static HRESULT RecursePath(
9 __in_z LPCWSTR wzPath, 12 __in_z LPCWSTR wzPath,
@@ -11,6 +14,7 @@ static HRESULT RecursePath(
11 __in_z LPCWSTR wzComponent, 14 __in_z LPCWSTR wzComponent,
12 __in_z LPCWSTR wzProperty, 15 __in_z LPCWSTR wzProperty,
13 __in int iMode, 16 __in int iMode,
17 __in BOOL fDisableWow64Redirection,
14 __inout DWORD* pdwCounter, 18 __inout DWORD* pdwCounter,
15 __inout MSIHANDLE* phTable, 19 __inout MSIHANDLE* phTable,
16 __inout MSIHANDLE* phColumns 20 __inout MSIHANDLE* phColumns
@@ -24,6 +28,12 @@ static HRESULT RecursePath(
24 WIN32_FIND_DATAW wfd; 28 WIN32_FIND_DATAW wfd;
25 LPWSTR sczNext = NULL; 29 LPWSTR sczNext = NULL;
26 30
31 if (fDisableWow64Redirection)
32 {
33 hr = WcaDisableWow64FSRedirection();
34 ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API.");
35 }
36
27 // First recurse down to all the child directories. 37 // First recurse down to all the child directories.
28 hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath); 38 hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath);
29 ExitOnFailure(hr, "Failed to allocate file search string in path: %S", wzPath); 39 ExitOnFailure(hr, "Failed to allocate file search string in path: %S", wzPath);
@@ -34,7 +44,7 @@ static HRESULT RecursePath(
34 er = ::GetLastError(); 44 er = ::GetLastError();
35 if (ERROR_PATH_NOT_FOUND == er) 45 if (ERROR_PATH_NOT_FOUND == er)
36 { 46 {
37 WcaLog(LOGMSG_STANDARD, "Search path not found: %ls", sczSearch); 47 WcaLog(LOGMSG_STANDARD, "Search path not found: %ls; skipping", sczSearch);
38 ExitFunction1(hr = S_FALSE); 48 ExitFunction1(hr = S_FALSE);
39 } 49 }
40 else 50 else
@@ -55,7 +65,8 @@ static HRESULT RecursePath(
55 hr = StrAllocFormatted(&sczNext, L"%s%s\\", wzPath, wfd.cFileName); 65 hr = StrAllocFormatted(&sczNext, L"%s%s\\", wzPath, wfd.cFileName);
56 ExitOnFailure(hr, "Failed to concat filename '%S' to string: %S", wfd.cFileName, wzPath); 66 ExitOnFailure(hr, "Failed to concat filename '%S' to string: %S", wfd.cFileName, wzPath);
57 67
58 hr = RecursePath(sczNext, wzId, wzComponent, wzProperty, iMode, pdwCounter, phTable, phColumns); 68 // Don't re-disable redirection; if it was necessary, we've already done it.
69 hr = RecursePath(sczNext, wzId, wzComponent, wzProperty, iMode, FALSE, pdwCounter, phTable, phColumns);
59 ExitOnFailure(hr, "Failed to recurse path: %S", sczNext); 70 ExitOnFailure(hr, "Failed to recurse path: %S", sczNext);
60 } while (::FindNextFileW(hFind, &wfd)); 71 } while (::FindNextFileW(hFind, &wfd));
61 72
@@ -81,10 +92,10 @@ static HRESULT RecursePath(
81 92
82 // Add the row to remove any files and another row to remove the folder. 93 // Add the row to remove any files and another row to remove the folder.
83 hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFiles", wzComponent, L"*.*", sczProperty, iMode); 94 hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFiles", wzComponent, L"*.*", sczProperty, iMode);
84 ExitOnFailure(hr, "Failed to add row to remove all files for Wix4RemoveFolderEx row: %S under path:", wzId, wzPath); 95 ExitOnFailure(hr, "Failed to add row to remove all files for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath);
85 96
86 hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFolder", wzComponent, NULL, sczProperty, iMode); 97 hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFolder", wzComponent, NULL, sczProperty, iMode);
87 ExitOnFailure(hr, "Failed to add row to remove folder for Wix4RemoveFolderEx row: %S under path: %S", wzId, wzPath); 98 ExitOnFailure(hr, "Failed to add row to remove folder for Wix4RemoveFolderEx row: %ls under path: %ls", wzId, wzPath);
88 99
89LExit: 100LExit:
90 if (INVALID_HANDLE_VALUE != hFind) 101 if (INVALID_HANDLE_VALUE != hFind)
@@ -92,6 +103,11 @@ LExit:
92 ::FindClose(hFind); 103 ::FindClose(hFind);
93 } 104 }
94 105
106 if (fDisableWow64Redirection)
107 {
108 WcaRevertWow64FSRedirection();
109 }
110
95 ReleaseStr(sczNext); 111 ReleaseStr(sczNext);
96 ReleaseStr(sczProperty); 112 ReleaseStr(sczProperty);
97 ReleaseStr(sczSearch); 113 ReleaseStr(sczSearch);
@@ -110,9 +126,12 @@ extern "C" UINT WINAPI WixRemoveFoldersEx(
110 LPWSTR sczId = NULL; 126 LPWSTR sczId = NULL;
111 LPWSTR sczComponent = NULL; 127 LPWSTR sczComponent = NULL;
112 LPWSTR sczProperty = NULL; 128 LPWSTR sczProperty = NULL;
129 LPWSTR sczCondition = NULL;
113 LPWSTR sczPath = NULL; 130 LPWSTR sczPath = NULL;
114 LPWSTR sczExpandedPath = NULL; 131 LPWSTR sczExpandedPath = NULL;
115 int iMode = 0; 132 int iMode = 0;
133 int iComponentAttributes;
134 BOOL f64BitComponent = FALSE;
116 DWORD dwCounter = 0; 135 DWORD dwCounter = 0;
117 DWORD_PTR cchLen = 0; 136 DWORD_PTR cchLen = 0;
118 MSIHANDLE hTable = NULL; 137 MSIHANDLE hTable = NULL;
@@ -121,6 +140,8 @@ extern "C" UINT WINAPI WixRemoveFoldersEx(
121 hr = WcaInitialize(hInstall, "WixRemoveFoldersEx"); 140 hr = WcaInitialize(hInstall, "WixRemoveFoldersEx");
122 ExitOnFailure(hr, "Failed to initialize WixRemoveFoldersEx."); 141 ExitOnFailure(hr, "Failed to initialize WixRemoveFoldersEx.");
123 142
143 WcaInitializeWow64();
144
124 // anything to do? 145 // anything to do?
125 if (S_OK != WcaTableExists(L"Wix4RemoveFolderEx")) 146 if (S_OK != WcaTableExists(L"Wix4RemoveFolderEx"))
126 { 147 {
@@ -137,18 +158,40 @@ extern "C" UINT WINAPI WixRemoveFoldersEx(
137 hr = WcaGetRecordString(hRec, rfqId, &sczId); 158 hr = WcaGetRecordString(hRec, rfqId, &sczId);
138 ExitOnFailure(hr, "Failed to get remove folder identity."); 159 ExitOnFailure(hr, "Failed to get remove folder identity.");
139 160
161 hr = WcaGetRecordString(hRec, rfqCondition, &sczCondition);
162 ExitOnFailure(hr, "Failed to get remove folder condition.");
163
164 if (sczCondition && *sczCondition)
165 {
166 MSICONDITION condition = ::MsiEvaluateConditionW(hInstall, sczCondition);
167 if (MSICONDITION_TRUE == condition)
168 {
169 WcaLog(LOGMSG_STANDARD, "True condition for row %S: %S; processing.", sczId, sczCondition);
170 }
171 else
172 {
173 WcaLog(LOGMSG_STANDARD, "False or invalid condition for row %S: %S; skipping.", sczId, sczCondition);
174 continue;
175 }
176 }
177
140 hr = WcaGetRecordString(hRec, rfqComponent, &sczComponent); 178 hr = WcaGetRecordString(hRec, rfqComponent, &sczComponent);
141 ExitOnFailure(hr, "Failed to get remove folder component."); 179 ExitOnFailure(hr, "Failed to get remove folder component.");
142 180
143 hr = WcaGetRecordString(hRec, rfqProperty, &sczProperty); 181 hr = WcaGetRecordString(hRec, rfqProperty, &sczProperty);
144 ExitOnFailure(hr, "Failed to get remove folder property."); 182 ExitOnFailure(hr, "Failed to get remove folder property.");
145 183
146 hr = WcaGetRecordInteger(hRec, feqMode, &iMode); 184 hr = WcaGetRecordInteger(hRec, rfqMode, &iMode);
147 ExitOnFailure(hr, "Failed to get remove folder mode"); 185 ExitOnFailure(hr, "Failed to get remove folder mode");
148 186
149 hr = WcaGetProperty(sczProperty, &sczPath); 187 hr = WcaGetProperty(sczProperty, &sczPath);
150 ExitOnFailure(hr, "Failed to resolve remove folder property: %S for row: %S", sczProperty, sczId); 188 ExitOnFailure(hr, "Failed to resolve remove folder property: %S for row: %S", sczProperty, sczId);
151 189
190 hr = WcaGetRecordInteger(hRec, rfqComponentAttributes, &iComponentAttributes);
191 ExitOnFailure(hr, "failed to get component attributes for row: %ls", sczId);
192
193 f64BitComponent = iComponentAttributes & msidbComponentAttributes64bit;
194
152 // fail early if the property isn't set as you probably don't want your installers trying to delete SystemFolder 195 // fail early if the property isn't set as you probably don't want your installers trying to delete SystemFolder
153 // StringCchLengthW succeeds only if the string is zero characters plus 1 for the terminating null 196 // StringCchLengthW succeeds only if the string is zero characters plus 1 for the terminating null
154 hr = ::StringCchLengthW(sczPath, 1, reinterpret_cast<UINT_PTR*>(&cchLen)); 197 hr = ::StringCchLengthW(sczPath, 1, reinterpret_cast<UINT_PTR*>(&cchLen));
@@ -164,7 +207,7 @@ extern "C" UINT WINAPI WixRemoveFoldersEx(
164 ExitOnFailure(hr, "Failed to backslash-terminate path: %S", sczExpandedPath); 207 ExitOnFailure(hr, "Failed to backslash-terminate path: %S", sczExpandedPath);
165 208
166 WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId); 209 WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId);
167 hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, &dwCounter, &hTable, &hColumns); 210 hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, f64BitComponent, &dwCounter, &hTable, &hColumns);
168 ExitOnFailure(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId); 211 ExitOnFailure(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId);
169 } 212 }
170 213
@@ -176,6 +219,8 @@ extern "C" UINT WINAPI WixRemoveFoldersEx(
176 ExitOnFailure(hr, "Failure occured while processing Wix4RemoveFolderEx table"); 219 ExitOnFailure(hr, "Failure occured while processing Wix4RemoveFolderEx table");
177 220
178LExit: 221LExit:
222 WcaFinalizeWow64();
223
179 if (hColumns) 224 if (hColumns)
180 { 225 {
181 ::MsiCloseHandle(hColumns); 226 ::MsiCloseHandle(hColumns);
@@ -190,6 +235,7 @@ LExit:
190 ReleaseStr(sczPath); 235 ReleaseStr(sczPath);
191 ReleaseStr(sczProperty); 236 ReleaseStr(sczProperty);
192 ReleaseStr(sczComponent); 237 ReleaseStr(sczComponent);
238 ReleaseStr(sczCondition);
193 ReleaseStr(sczId); 239 ReleaseStr(sczId);
194 240
195 DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; 241 DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
diff --git a/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs b/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs
index b2af91b3..9c32ebc2 100644
--- a/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs
+++ b/src/test/WixToolsetTest.Util/UtilExtensionFixture.cs
@@ -139,8 +139,8 @@ namespace WixToolsetTest.Util
139 WixAssert.CompareLineByLine(new[] 139 WixAssert.CompareLineByLine(new[]
140 { 140 {
141 "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]", 141 "Binary:Wix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t[Binary data]",
142 "CustomAction:Wix4RemoveFoldersEx_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t65\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A WixRemoveFoldersEx\t", 142 "CustomAction:Wix4RemoveFoldersEx_X64.047730A5_30FE_4A62_A520_DA9381B8226A\t65\tWix4UtilCA_X64.047730A5_30FE_4A62_A520_DA9381B8226A\tWixRemoveFoldersEx\t",
143 "Wix4RemoveFolderEx:wrfB3e9CDihkNwm06LohylbJcjZ91w.047730A5_30FE_4A62_A520_DA9381B8226A\tfilh4juyUVjoUcWWtcQmd5L07FoON4.047730A5_30FE_4A62_A520_DA9381B8226A\tRemoveProp.047730A5_30FE_4A62_A520_DA9381B8226A\t3", 143 "Wix4RemoveFolderEx:wrf5qCm1SE.zp8djrlk78l1IYFXsEw.047730A5_30FE_4A62_A520_DA9381B8226A\tfilh4juyUVjoUcWWtcQmd5L07FoON4.047730A5_30FE_4A62_A520_DA9381B8226A\tRemoveProp.047730A5_30FE_4A62_A520_DA9381B8226A\t3\t",
144 }, results.OrderBy(s => s).ToArray()); 144 }, results.OrderBy(s => s).ToArray());
145 } 145 }
146 146
diff --git a/src/wixext/Symbols/WixRemoveFolderExSymbol.cs b/src/wixext/Symbols/WixRemoveFolderExSymbol.cs
index 0c50ab8e..86352b6c 100644
--- a/src/wixext/Symbols/WixRemoveFolderExSymbol.cs
+++ b/src/wixext/Symbols/WixRemoveFolderExSymbol.cs
@@ -14,6 +14,7 @@ namespace WixToolset.Util
14 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.ComponentRef), IntermediateFieldType.String), 14 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.Property), IntermediateFieldType.String), 15 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.Property), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.InstallMode), IntermediateFieldType.Number), 16 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.InstallMode), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(WixRemoveFolderExSymbolFields.Condition), IntermediateFieldType.String),
17 }, 18 },
18 typeof(WixRemoveFolderExSymbol)); 19 typeof(WixRemoveFolderExSymbol));
19 } 20 }
@@ -28,6 +29,14 @@ namespace WixToolset.Util.Symbols
28 ComponentRef, 29 ComponentRef,
29 Property, 30 Property,
30 InstallMode, 31 InstallMode,
32 Condition,
33 }
34
35 public enum WixRemoveFolderExInstallMode
36 {
37 Install = 1,
38 Uninstall = 2,
39 Both = 3,
31 } 40 }
32 41
33 public class WixRemoveFolderExSymbol : IntermediateSymbol 42 public class WixRemoveFolderExSymbol : IntermediateSymbol
@@ -54,10 +63,16 @@ namespace WixToolset.Util.Symbols
54 set => this.Set((int)WixRemoveFolderExSymbolFields.Property, value); 63 set => this.Set((int)WixRemoveFolderExSymbolFields.Property, value);
55 } 64 }
56 65
57 public int InstallMode 66 public WixRemoveFolderExInstallMode InstallMode
67 {
68 get => (WixRemoveFolderExInstallMode)this.Fields[(int)WixRemoveFolderExSymbolFields.InstallMode].AsNumber();
69 set => this.Set((int)WixRemoveFolderExSymbolFields.InstallMode, (int)value);
70 }
71
72 public string Condition
58 { 73 {
59 get => this.Fields[(int)WixRemoveFolderExSymbolFields.InstallMode].AsNumber(); 74 get => this.Fields[(int)WixRemoveFolderExSymbolFields.Condition].AsString();
60 set => this.Set((int)WixRemoveFolderExSymbolFields.InstallMode, value); 75 set => this.Set((int)WixRemoveFolderExSymbolFields.Condition, value);
61 } 76 }
62 } 77 }
63} \ No newline at end of file 78} \ No newline at end of file
diff --git a/src/wixext/UtilCompiler.cs b/src/wixext/UtilCompiler.cs
index 12213e63..63f2b469 100644
--- a/src/wixext/UtilCompiler.cs
+++ b/src/wixext/UtilCompiler.cs
@@ -41,13 +41,6 @@ namespace WixToolset.Util
41 Compatible, 41 Compatible,
42 } 42 }
43 43
44 internal enum WixRemoveFolderExOn
45 {
46 Install = 1,
47 Uninstall = 2,
48 Both = 3,
49 }
50
51 private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled); 44 private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled);
52 45
53 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/util"; 46 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/util";
@@ -2812,8 +2805,9 @@ namespace WixToolset.Util
2812 { 2805 {
2813 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); 2806 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2814 Identifier id = null; 2807 Identifier id = null;
2815 var on = (int)WixRemoveFolderExOn.Uninstall; 2808 var mode = WixRemoveFolderExInstallMode.Uninstall;
2816 string property = null; 2809 string property = null;
2810 string condition = null;
2817 2811
2818 foreach (var attrib in element.Attributes()) 2812 foreach (var attrib in element.Attributes())
2819 { 2813 {
@@ -2821,6 +2815,9 @@ namespace WixToolset.Util
2821 { 2815 {
2822 switch (attrib.Name.LocalName) 2816 switch (attrib.Name.LocalName)
2823 { 2817 {
2818 case "Condition":
2819 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2820 break;
2824 case "Id": 2821 case "Id":
2825 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib); 2822 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2826 break; 2823 break;
@@ -2828,24 +2825,22 @@ namespace WixToolset.Util
2828 var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); 2825 var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2829 if (onValue.Length == 0) 2826 if (onValue.Length == 0)
2830 { 2827 {
2831 on = CompilerConstants.IllegalInteger;
2832 } 2828 }
2833 else 2829 else
2834 { 2830 {
2835 switch (onValue) 2831 switch (onValue)
2836 { 2832 {
2837 case "install": 2833 case "install":
2838 on = (int)WixRemoveFolderExOn.Install; 2834 mode = WixRemoveFolderExInstallMode.Install;
2839 break; 2835 break;
2840 case "uninstall": 2836 case "uninstall":
2841 on = (int)WixRemoveFolderExOn.Uninstall; 2837 mode = WixRemoveFolderExInstallMode.Uninstall;
2842 break; 2838 break;
2843 case "both": 2839 case "both":
2844 on = (int)WixRemoveFolderExOn.Both; 2840 mode = WixRemoveFolderExInstallMode.Both;
2845 break; 2841 break;
2846 default: 2842 default:
2847 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", onValue, "install", "uninstall", "both")); 2843 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", onValue, "install", "uninstall", "both"));
2848 on = CompilerConstants.IllegalInteger;
2849 break; 2844 break;
2850 } 2845 }
2851 } 2846 }
@@ -2869,9 +2864,9 @@ namespace WixToolset.Util
2869 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Property")); 2864 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Property"));
2870 } 2865 }
2871 2866
2872 if (null == id) 2867 if (id == null)
2873 { 2868 {
2874 id = this.ParseHelper.CreateIdentifier("wrf", componentId, property, on.ToString(CultureInfo.InvariantCulture.NumberFormat)); 2869 id = this.ParseHelper.CreateIdentifier("wrf", componentId, property, mode.ToString());
2875 } 2870 }
2876 2871
2877 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); 2872 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
@@ -2884,7 +2879,8 @@ namespace WixToolset.Util
2884 { 2879 {
2885 ComponentRef = componentId, 2880 ComponentRef = componentId,
2886 Property = property, 2881 Property = property,
2887 InstallMode = on, 2882 InstallMode = mode,
2883 Condition = condition
2888 }); 2884 });
2889 2885
2890 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveFile"); 2886 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveFile");
diff --git a/src/wixext/UtilTableDefinitions.cs b/src/wixext/UtilTableDefinitions.cs
index eff5aaf6..fd09367a 100644
--- a/src/wixext/UtilTableDefinitions.cs
+++ b/src/wixext/UtilTableDefinitions.cs
@@ -33,6 +33,7 @@ namespace WixToolset.Util
33 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), 33 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),
34 new ColumnDefinition("Property", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, description: "Name of Property that contains the root of the directory tree to remove.", modularizeType: ColumnModularizeType.Column), 34 new ColumnDefinition("Property", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, description: "Name of Property that contains the root of the directory tree to remove.", modularizeType: ColumnModularizeType.Column),
35 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."), 35 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."),
36 new ColumnDefinition("Condition", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Condition, description: "Optional expression which skips the removing of folders.", modularizeType: ColumnModularizeType.Condition, forceLocalizable: true),
36 }, 37 },
37 symbolIdIsPrimaryKey: true 38 symbolIdIsPrimaryKey: true
38 ); 39 );