Modularize XmlConfig/@ElementId and add tests for XmlConfig
Fixes wixtoolset/issues#4698 Closes wixtoolset/issues#5447
Rob Mensching committed
Jan 9, 2021 at 01:37 UTC
923d3edd21da412b0fd6a09dfd3391913fe18c56
10 files changed
+175
-77
src/ca/XmlConfig.cpp
+61
-40
@@ -30,10 +30,10 @@ enum eXmlPreserveDate
30
};
31
32
LPCWSTR vcsXmlConfigQuery =
33
- L"SELECT `Wix4XmlConfig`.`Wix4XmlConfig`, `Wix4XmlConfig`.`File`, `Wix4XmlConfig`.`ElementPath`, `Wix4XmlConfig`.`VerifyPath`, `Wix4XmlConfig`.`Name`, "
33
+ L"SELECT `Wix4XmlConfig`.`Wix4XmlConfig`, `Wix4XmlConfig`.`File`, `Wix4XmlConfig`.`ElementId`, `Wix4XmlConfig`.`ElementPath`, `Wix4XmlConfig`.`VerifyPath`, `Wix4XmlConfig`.`Name`, "
34
L"`Wix4XmlConfig`.`Value`, `Wix4XmlConfig`.`Flags`, `Wix4XmlConfig`.`Component_`, `Component`.`Attributes` "
35
L"FROM `Wix4XmlConfig`,`Component` WHERE `Wix4XmlConfig`.`Component_`=`Component`.`Component` ORDER BY `File`, `Sequence`";
36
-enum eXmlConfigQuery { xfqXmlConfig = 1, xfqFile, xfqElementPath, xfqVerifyPath, xfqName, xfqValue, xfqXmlFlags, xfqComponent, xfqCompAttributes };
36
+enum eXmlConfigQuery { xfqXmlConfig = 1, xfqFile, xfqElementId, xfqElementPath, xfqVerifyPath, xfqName, xfqValue, xfqXmlFlags, xfqComponent, xfqCompAttributes };
37
38
struct XML_CONFIG_CHANGE
39
{
@@ -44,6 +44,7 @@ struct XML_CONFIG_CHANGE
44
INSTALLSTATE isAction;
45
46
WCHAR wzFile[MAX_PATH];
47
+ LPWSTR pwzElementId;
48
LPWSTR pwzElementPath;
49
LPWSTR pwzVerifyPath;
50
WCHAR wzName[MAX_DARWIN_COLUMN];
@@ -72,26 +73,32 @@ static HRESULT FreeXmlConfigChangeList(
73
pxfcDelete = pxfcList;
74
pxfcList = pxfcList->pxfcNext;
75
76
+ if (pxfcDelete->pwzElementId)
77
+ {
78
+ hr = MemFree(pxfcDelete->pwzElementId);
79
+ ExitOnFailure(hr, "failed to free xml config element id in change list item");
80
+ }
81
+
82
if (pxfcDelete->pwzElementPath)
83
{
84
hr = MemFree(pxfcDelete->pwzElementPath);
78
- ExitOnFailure(hr, "failed to free xml file element path in change list item");
85
+ ExitOnFailure(hr, "failed to free xml config element path in change list item");
86
}
87
88
if (pxfcDelete->pwzVerifyPath)
89
{
90
hr = MemFree(pxfcDelete->pwzVerifyPath);
84
- ExitOnFailure(hr, "failed to free xml file verify path in change list item");
91
+ ExitOnFailure(hr, "failed to free xml config verify path in change list item");
92
}
93
94
if (pxfcDelete->pwzValue)
95
{
96
hr = MemFree(pxfcDelete->pwzValue);
90
- ExitOnFailure(hr, "failed to free xml file value in change list item");
97
+ ExitOnFailure(hr, "failed to free xml config value in change list item");
98
}
99
100
hr = MemFree(pxfcDelete);
94
- ExitOnFailure(hr, "failed to free xml file change list item");
101
+ ExitOnFailure(hr, "failed to free xml config change list item");
102
}
103
104
LExit:
@@ -191,6 +198,10 @@ static HRESULT ReadXmlConfigTable(
198
hr = WcaGetRecordInteger(hRec, xfqXmlFlags, &(*ppxfcTail)->iXmlFlags);
199
ExitOnFailure(hr, "failed to get Wix4XmlConfig flags for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
200
201
+ // Get the Element Id
202
+ hr = WcaGetRecordFormattedString(hRec, xfqElementId, &(*ppxfcTail)->pwzElementId);
203
+ ExitOnFailure(hr, "failed to get Element Id for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
204
+
205
// Get the Element Path
206
hr = WcaGetRecordFormattedString(hRec, xfqElementPath, &(*ppxfcTail)->pwzElementPath);
207
ExitOnFailure(hr, "failed to get Element Path for Wix4XmlConfig: %ls", (*ppxfcTail)->wzId);
@@ -259,45 +270,55 @@ static HRESULT ProcessChanges(
270
pxfcCheck = *ppxfcHead;
271
while (pxfcCheck)
272
{
262
- if (0 == lstrcmpW(pxfc->pwzElementPath, pxfcCheck->wzId) && 0 == pxfc->iXmlFlags
263
- && XMLCONFIG_CREATE & pxfcCheck->iXmlFlags && XMLCONFIG_ELEMENT & pxfcCheck->iXmlFlags)
273
+ if (pxfc->pwzElementId)
274
{
265
- // We found a match. First, take it out of the current list
266
- if (pxfc->pxfcPrev)
275
+ if (0 == lstrcmpW(pxfc->pwzElementId, pxfcCheck->wzId)
276
+ && 0 == pxfc->iXmlFlags
277
+ && XMLCONFIG_CREATE & pxfcCheck->iXmlFlags
278
+ && XMLCONFIG_ELEMENT & pxfcCheck->iXmlFlags)
279
{
268
- pxfc->pxfcPrev->pxfcNext = pxfc->pxfcNext;
269
- }
270
- else // it was the head. Update the head
271
- {
272
- *ppxfcHead = pxfc->pxfcNext;
273
- }
280
+ // We found a match. First, take it out of the current list
281
+ if (pxfc->pxfcPrev)
282
+ {
283
+ pxfc->pxfcPrev->pxfcNext = pxfc->pxfcNext;
284
+ }
285
+ else // it was the head. Update the head
286
+ {
287
+ *ppxfcHead = pxfc->pxfcNext;
288
+ }
289
275
- if (pxfc->pxfcNext)
276
- {
277
- pxfc->pxfcNext->pxfcPrev = pxfc->pxfcPrev;
278
- }
290
+ if (pxfc->pxfcNext)
291
+ {
292
+ pxfc->pxfcNext->pxfcPrev = pxfc->pxfcPrev;
293
+ }
294
280
- pxfc->pxfcNext = NULL;
281
- pxfc->pxfcPrev = NULL;
295
+ pxfc->pxfcNext = NULL;
296
+ pxfc->pxfcPrev = NULL;
297
283
- // Now, add this node to the end of the matched node's additional changes list
284
- if (!pxfcCheck->pxfcAdditionalChanges)
285
- {
286
- pxfcCheck->pxfcAdditionalChanges = pxfc;
287
- pxfcCheck->cAdditionalChanges = 1;
298
+ // Now, add this node to the end of the matched node's additional changes list
299
+ if (!pxfcCheck->pxfcAdditionalChanges)
300
+ {
301
+ pxfcCheck->pxfcAdditionalChanges = pxfc;
302
+ pxfcCheck->cAdditionalChanges = 1;
303
+ }
304
+ else
305
+ {
306
+ pxfcLast = pxfcCheck->pxfcAdditionalChanges;
307
+ cAdditionalChanges = 1;
308
+ while (pxfcLast->pxfcNext)
309
+ {
310
+ pxfcLast = pxfcLast->pxfcNext;
311
+ ++cAdditionalChanges;
312
+ }
313
+ pxfcLast->pxfcNext = pxfc;
314
+ pxfc->pxfcPrev = pxfcLast;
315
+ pxfcCheck->cAdditionalChanges = ++cAdditionalChanges;
316
+ }
317
}
318
else
319
{
291
- pxfcLast = pxfcCheck->pxfcAdditionalChanges;
292
- cAdditionalChanges = 1;
293
- while (pxfcLast->pxfcNext)
294
- {
295
- pxfcLast = pxfcLast->pxfcNext;
296
- ++cAdditionalChanges;
297
- }
298
- pxfcLast->pxfcNext = pxfc;
299
- pxfc->pxfcPrev = pxfcLast;
300
- pxfcCheck->cAdditionalChanges = ++cAdditionalChanges;
320
+ hr = E_NOTFOUND;
321
+ ExitOnRootFailure(hr, "failed to find matching ElementId: %ls", pxfc->pwzElementId);
322
}
323
}
324
@@ -381,9 +402,10 @@ static HRESULT WriteChangeData(
402
403
HRESULT hr = S_OK;
404
XML_CONFIG_CHANGE* pxfcAdditionalChanges = NULL;
405
+ LPCWSTR wzElementPath = pxfc->pwzElementId ? pxfc->pwzElementId : pxfc->pwzElementPath;
406
385
- hr = WcaWriteStringToCaData(pxfc->pwzElementPath, ppwzCustomActionData);
386
- ExitOnFailure(hr, "failed to write ElementPath to custom action data: %ls", pxfc->pwzElementPath);
407
+ hr = WcaWriteStringToCaData(wzElementPath, ppwzCustomActionData);
408
+ ExitOnFailure(hr, "failed to write ElementPath to custom action data: %ls", wzElementPath);
409
410
hr = WcaWriteStringToCaData(pxfc->pwzVerifyPath, ppwzCustomActionData);
411
ExitOnFailure(hr, "failed to write VerifyPath to custom action data: %ls", pxfc->pwzVerifyPath);
@@ -1111,4 +1133,3 @@ LExit:
1133
}
1134
return WcaFinalize(er);
1135
}
1114
-
src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.en-us.wxl
new
+11
@@ -0,0 +1,11 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+
3
+<!--
4
+This file contains the declaration of all the localizable strings.
5
+-->
6
+<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7
+
8
+ <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
9
+ <String Id="FeatureTitle">MsiPackage</String>
10
+
11
+</WixLocalization>
src/test/WixToolsetTest.Util/TestData/XmlConfig/Package.wxs
new
+27
@@ -0,0 +1,27 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2
+ <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3
+ <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
+
5
+ <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6
+ <Component Id="Del" Directory="INSTALLFOLDER" Guid="3613414c-11f5-40fa-a1f1-a0ba722a6895">
7
+ <util:XmlConfig
8
+ Id="DelElement"
9
+ File="[INSTALLFOLDER]my.xml"
10
+ Action="delete"
11
+ Node="element"
12
+ VerifyPath="xxx"
13
+ ElementPath="//root/sub"
14
+ On="install"
15
+ Sequence="1" />
16
+ </Component>
17
+ </Feature>
18
+ </Package>
19
+
20
+ <Fragment>
21
+ <Directory Id="TARGETDIR" Name="SourceDir">
22
+ <Directory Id="ProgramFilesFolder">
23
+ <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
24
+ </Directory>
25
+ </Directory>
26
+ </Fragment>
27
+</Wix>
src/test/WixToolsetTest.Util/TestData/XmlConfigModule/Module.wxs
new
+34
@@ -0,0 +1,34 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
2
+ <Module Id="XmlConfigModule" Language="1033" Version="1.0.0.0" Guid="047730a5-30fe-4a62-a520-da9381b8226a">
3
+
4
+ <Component Id="Parent" Directory="INSTALLFOLDER">
5
+ <File Id="my.xml" Source="my.xml" />
6
+ <util:XmlConfig
7
+ Id="AddElement"
8
+ File="[my.xml]"
9
+ Action="create"
10
+ Node="element"
11
+ VerifyPath="xxx"
12
+ ElementPath="//root/sub"
13
+ On="install"
14
+ Sequence="1" />
15
+ </Component>
16
+
17
+ <Component Id="Child" Directory="INSTALLFOLDER" Guid="4613414c-11f5-40fa-a1f1-a0ba722a6895">
18
+ <util:XmlConfig
19
+ Id="ChildElement"
20
+ File="[my.xml]"
21
+ VerifyPath="xxx"
22
+ ElementId="AddElement"
23
+ Sequence="1" />
24
+ </Component>
25
+ </Module>
26
+
27
+ <Fragment>
28
+ <Directory Id="TARGETDIR" Name="SourceDir">
29
+ <Directory Id="ProgramFilesFolder">
30
+ <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
31
+ </Directory>
32
+ </Directory>
33
+ </Fragment>
34
+</Wix>
src/test/WixToolsetTest.Util/TestData/XmlConfigModule/my.xml
new
+1
@@ -0,0 +1 @@
1
+This is my.xml file.
src/test/WixToolsetTest.Util/UtilExtensionFixture.cs
+27
@@ -172,6 +172,33 @@ namespace WixToolsetTest.Util
172
}, results.OrderBy(s => s).ToArray());
173
}
174
175
+ [Fact]
176
+ public void CanBuildWithXmlConfig()
177
+ {
178
+ var folder = TestData.Get(@"TestData", "XmlConfig");
179
+ var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
180
+
181
+ var results = build.BuildAndQuery(BuildX64, "Wix4XmlConfig");
182
+ WixAssert.CompareLineByLine(new[]
183
+ {
184
+ "Wix4XmlConfig:DelElement\t[INSTALLFOLDER]my.xml\t\t//root/sub\txxx\t\t\t289\tDel\t1",
185
+ }, results.OrderBy(s => s).ToArray());
186
+ }
187
+
188
+ [Fact]
189
+ public void CanBuildModuleWithXmlConfig()
190
+ {
191
+ var folder = TestData.Get(@"TestData", "XmlConfigModule");
192
+ var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder });
193
+
194
+ var results = build.BuildAndQuery(BuildX64, "Wix4XmlConfig");
195
+ WixAssert.CompareLineByLine(new[]
196
+ {
197
+ "Wix4XmlConfig:AddElement.047730A5_30FE_4A62_A520_DA9381B8226A\t[my.xml.047730A5_30FE_4A62_A520_DA9381B8226A]\t\t//root/sub\txxx\t\t\t273\tParent.047730A5_30FE_4A62_A520_DA9381B8226A\t1",
198
+ "Wix4XmlConfig:ChildElement.047730A5_30FE_4A62_A520_DA9381B8226A\t[my.xml.047730A5_30FE_4A62_A520_DA9381B8226A]\tAddElement.047730A5_30FE_4A62_A520_DA9381B8226A\t\txxx\t\t\t0\tChild.047730A5_30FE_4A62_A520_DA9381B8226A\t1",
199
+ }, results.OrderBy(s => s).ToArray());
200
+ }
201
+
202
[Fact]
203
public void CanBuildBundleWithSearches()
204
{
src/test/WixToolsetTest.Util/WixToolsetTest.Util.csproj
+1
-35
@@ -12,41 +12,7 @@
12
</PropertyGroup>
13
14
<ItemGroup>
15
- <Content Include="TestData\.Data\burn.exe" CopyToOutputDirectory="PreserveNewest" />
16
- <Content Include="TestData\BundleWithSearches\data\fakeba.dll" CopyToOutputDirectory="PreserveNewest" />
17
- <Content Include="TestData\BundleWithSearches\data\MsiPackage\Shared.dll" CopyToOutputDirectory="PreserveNewest" />
18
- <Content Include="TestData\BundleWithSearches\data\MsiPackage\test.txt" CopyToOutputDirectory="PreserveNewest" />
19
- <Content Include="TestData\BundleWithSearches\data\test.msi" CopyToOutputDirectory="PreserveNewest" />
20
- <Content Include="TestData\BundleWithSearches\Bundle.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
21
- <Content Include="TestData\BundleWithSearches\Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />
22
- <Content Include="TestData\UsingFileShare\example.txt" CopyToOutputDirectory="PreserveNewest" />
23
- <Content Include="TestData\UsingFileShare\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
24
- <Content Include="TestData\UsingFileShare\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
25
- <Content Include="TestData\UsingFileShare\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
26
- <Content Include="TestData\CloseApplication\example.txt" CopyToOutputDirectory="PreserveNewest" />
27
- <Content Include="TestData\CloseApplication\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
28
- <Content Include="TestData\CloseApplication\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
29
- <Content Include="TestData\CloseApplication\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
30
- <Content Include="TestData\InternetShortcut\Package.ico" CopyToOutputDirectory="PreserveNewest" />
31
- <Content Include="TestData\InternetShortcut\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
32
- <Content Include="TestData\InternetShortcut\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
33
- <Content Include="TestData\InternetShortcut\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
34
- <Content Include="TestData\InternetShortcutModule\Package.ico" CopyToOutputDirectory="PreserveNewest" />
35
- <Content Include="TestData\InternetShortcutModule\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
36
- <Content Include="TestData\InternetShortcutModule\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
37
- <Content Include="TestData\InternetShortcutModule\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
38
- <Content Include="TestData\PermissionEx\example.txt" CopyToOutputDirectory="PreserveNewest" />
39
- <Content Include="TestData\PermissionEx\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
40
- <Content Include="TestData\PermissionEx\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
41
- <Content Include="TestData\PermissionEx\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
42
- <Content Include="TestData\EventManifest\example.txt" CopyToOutputDirectory="PreserveNewest" />
43
- <Content Include="TestData\EventManifest\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
44
- <Content Include="TestData\EventManifest\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
45
- <Content Include="TestData\EventManifest\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
46
- <Content Include="TestData\Queries\example.txt" CopyToOutputDirectory="PreserveNewest" />
47
- <Content Include="TestData\Queries\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
48
- <Content Include="TestData\Queries\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
49
- <Content Include="TestData\Queries\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
15
+ <Content Include="TestData\**" CopyToOutputDirectory="PreserveNewest" />
16
</ItemGroup>
17
18
<ItemGroup>
src/wixext/Symbols/XmlConfigSymbol.cs
+8
@@ -12,6 +12,7 @@ namespace WixToolset.Util
12
new[]
13
{
14
new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.File), IntermediateFieldType.String),
15
+ new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ElementId), IntermediateFieldType.String),
16
new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.ElementPath), IntermediateFieldType.String),
17
new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.VerifyPath), IntermediateFieldType.String),
18
new IntermediateFieldDefinition(nameof(XmlConfigSymbolFields.Name), IntermediateFieldType.String),
@@ -31,6 +32,7 @@ namespace WixToolset.Util.Symbols
32
public enum XmlConfigSymbolFields
33
{
34
File,
35
+ ElementId,
36
ElementPath,
37
VerifyPath,
38
Name,
@@ -58,6 +60,12 @@ namespace WixToolset.Util.Symbols
60
set => this.Set((int)XmlConfigSymbolFields.File, value);
61
}
62
63
+ public string ElementId
64
+ {
65
+ get => this.Fields[(int)XmlConfigSymbolFields.ElementId].AsString();
66
+ set => this.Set((int)XmlConfigSymbolFields.ElementId, value);
67
+ }
68
+
69
public string ElementPath
70
{
71
get => this.Fields[(int)XmlConfigSymbolFields.ElementPath].AsString();
src/wixext/UtilCompiler.cs
+3
-1
@@ -3706,13 +3706,15 @@ namespace WixToolset.Util
3706
var symbol = section.AddSymbol(new XmlConfigSymbol(sourceLineNumbers, id)
3707
{
3708
File = file,
3709
- ElementPath = elementId ?? elementPath,
3709
+ ElementId = elementId,
3710
+ ElementPath = elementPath,
3711
VerifyPath = verifyPath,
3712
Name = name,
3713
Value = value,
3714
Flags = flags,
3715
ComponentRef = componentId,
3716
});
3717
+
3718
if (CompilerConstants.IntegerNotSet != sequence)
3719
{
3720
symbol.Sequence = sequence;
src/wixext/UtilTableDefinitions.cs
+2
-1
@@ -253,7 +253,8 @@ namespace WixToolset.Util
253
{
254
new ColumnDefinition("Wix4XmlConfig", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token.", modularizeType: ColumnModularizeType.Column),
255
new ColumnDefinition("File", ColumnType.Localized, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The .XML file in which to write the information", modularizeType: ColumnModularizeType.Property),
256
- new ColumnDefinition("ElementPath", ColumnType.Localized, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The XPATH query for an element to modify or add children to. Can also be a foreign key reference to another Wix4XmlConfig row if no attributes are set and the row referenced is a create element row.", modularizeType: ColumnModularizeType.Property),
256
+ new ColumnDefinition("ElementId", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Wix4XmlConfig", keyColumn: 1, description: "A foreign key reference to another Wix4XmlConfig row if no attributes are set and the row referenced is a create element row.", modularizeType: ColumnModularizeType.Column),
257
+ new ColumnDefinition("ElementPath", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The XPATH query for an element to modify or add children to. Must be null if ElementId is provided", modularizeType: ColumnModularizeType.Property),
258
new ColumnDefinition("VerifyPath", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The XPATH query run from ElementPath to verify whether a repair is necessary. Also used to uninstall.", modularizeType: ColumnModularizeType.Property),
259
new ColumnDefinition("Name", ColumnType.Localized, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The .XML file node to set/add in the element.", modularizeType: ColumnModularizeType.Property),
260
new ColumnDefinition("Value", ColumnType.Localized, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "The value to be written.", modularizeType: ColumnModularizeType.Property),