@joebigelow / wix / commits / 4449fcc5

Enable codepages and languages to be set via .wxl files

Fixes wixtoolset/issues#5801

Rob Mensching committed Apr 2, 2021 at 14:41 UTC 4449fcc5b8d104817c67135229682c66c3d892ca
38 files changed +619 -235
src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj
-1
@@ -22,7 +22,6 @@
22 </ItemGroup>
23
24 <ItemGroup>
25 - <PackageReference Include="System.Security.Permissions" Version="4.6.0" />
25 <PackageReference Include="WixToolset.Burn" Version="4.0.*" />
26 <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" />
27 <PackageReference Include="WixToolset.Data" Version="4.0.*" />
src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs
+13 -13
@@ -91,15 +91,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind
91 var symbols = this.Intermediate.Sections.SelectMany(s => s.Symbols).ToList();
92
93 // Get the patch id from the WixPatchId symbol.
94 - var patchIdSymbol = symbols.OfType<WixPatchIdSymbol>().FirstOrDefault();
94 + var patchSymbol = symbols.OfType<WixPatchSymbol>().FirstOrDefault();
95
96 - if (String.IsNullOrEmpty(patchIdSymbol.Id?.Id))
96 + if (String.IsNullOrEmpty(patchSymbol.Id?.Id))
97 {
98 this.Messaging.Write(ErrorMessages.ExpectedPatchIdInWixMsp());
99 return subStorages;
100 }
101
102 - if (String.IsNullOrEmpty(patchIdSymbol.ClientPatchId))
102 + if (String.IsNullOrEmpty(patchSymbol.ClientPatchId))
103 {
104 this.Messaging.Write(ErrorMessages.ExpectedClientPatchIdInWixMsp());
105 return subStorages;
@@ -115,7 +115,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
115 }
116
117 // populate MSP summary information
118 - var patchMetadata = this.PopulateSummaryInformation(summaryInfo, symbols, patchIdSymbol, section.Codepage);
118 + var patchMetadata = this.PopulateSummaryInformation(summaryInfo, symbols, patchSymbol);
119
120 // enumerate transforms
121 var productCodes = new SortedSet<string>();
@@ -168,7 +168,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
168 mainTransform.Transform.Tables.Remove("Media");
169 mainTransform.Transform.Tables.Remove("MsiDigitalSignature");
170
171 - var pairedTransform = this.BuildPairedTransform(summaryInfo, patchMetadata, patchIdSymbol, mainTransform.Transform, mediaSymbol, baselineSymbol, out var productCode);
171 + var pairedTransform = this.BuildPairedTransform(summaryInfo, patchMetadata, patchSymbol, mainTransform.Transform, mediaSymbol, baselineSymbol, out var productCode);
172
173 productCode = productCode.ToUpperInvariant();
174 productCodes.Add(productCode);
@@ -211,14 +211,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind
211 productCodes = FinalizePatchProductCodes(symbols, productCodes);
212
213 // Semicolon delimited list of the product codes that can accept the patch.
214 - summaryInfo.Add(SummaryInformationType.PatchProductCodes, new SummaryInformationSymbol(patchIdSymbol.SourceLineNumbers)
214 + summaryInfo.Add(SummaryInformationType.PatchProductCodes, new SummaryInformationSymbol(patchSymbol.SourceLineNumbers)
215 {
216 PropertyId = SummaryInformationType.PatchProductCodes,
217 Value = String.Join(";", productCodes)
218 });
219
220 // Semicolon delimited list of transform substorage names in the order they are applied.
221 - summaryInfo.Add(SummaryInformationType.TransformNames, new SummaryInformationSymbol(patchIdSymbol.SourceLineNumbers)
221 + summaryInfo.Add(SummaryInformationType.TransformNames, new SummaryInformationSymbol(patchSymbol.SourceLineNumbers)
222 {
223 PropertyId = SummaryInformationType.TransformNames,
224 Value = String.Join(";", transformNames)
@@ -262,25 +262,25 @@ namespace WixToolset.Core.WindowsInstaller.Bind
262 return result;
263 }
264
265 - private Dictionary<string, MsiPatchMetadataSymbol> PopulateSummaryInformation(Dictionary<SummaryInformationType, SummaryInformationSymbol> summaryInfo, List<IntermediateSymbol> symbols, WixPatchIdSymbol patchIdSymbol, int codepage)
265 + private Dictionary<string, MsiPatchMetadataSymbol> PopulateSummaryInformation(Dictionary<SummaryInformationType, SummaryInformationSymbol> summaryInfo, List<IntermediateSymbol> symbols, WixPatchSymbol patchSymbol)
266 {
267 // PID_CODEPAGE
268 if (!summaryInfo.ContainsKey(SummaryInformationType.Codepage))
269 {
270 // Set the code page by default to the same code page for the
271 // string pool in the database.
272 - AddSummaryInformation(SummaryInformationType.Codepage, codepage.ToString(CultureInfo.InvariantCulture), patchIdSymbol.SourceLineNumbers);
272 + AddSummaryInformation(SummaryInformationType.Codepage, patchSymbol.Codepage?.ToString(CultureInfo.InvariantCulture) ?? "0", patchSymbol.SourceLineNumbers);
273 }
274
275 // GUID patch code for the patch.
276 - AddSummaryInformation(SummaryInformationType.PatchCode, patchIdSymbol.Id.Id, patchIdSymbol.SourceLineNumbers);
276 + AddSummaryInformation(SummaryInformationType.PatchCode, patchSymbol.Id.Id, patchSymbol.SourceLineNumbers);
277
278 // Indicates the minimum Windows Installer version that is required to install the patch.
279 - AddSummaryInformation(SummaryInformationType.PatchInstallerRequirement, ((int)SummaryInformation.InstallerRequirement.Version31).ToString(CultureInfo.InvariantCulture), patchIdSymbol.SourceLineNumbers);
279 + AddSummaryInformation(SummaryInformationType.PatchInstallerRequirement, ((int)SummaryInformation.InstallerRequirement.Version31).ToString(CultureInfo.InvariantCulture), patchSymbol.SourceLineNumbers);
280
281 if (!summaryInfo.ContainsKey(SummaryInformationType.Security))
282 {
283 - AddSummaryInformation(SummaryInformationType.Security, "4", patchIdSymbol.SourceLineNumbers); // Read-only enforced;
283 + AddSummaryInformation(SummaryInformationType.Security, "4", patchSymbol.SourceLineNumbers); // Read-only enforced;
284 }
285
286 // Use authored comments or default to display name.
@@ -1090,7 +1090,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1090 /// <summary>
1091 /// Create the #transform for the given main transform.
1092 /// </summary>
1093 - private WindowsInstallerData BuildPairedTransform(Dictionary<SummaryInformationType, SummaryInformationSymbol> summaryInfo, Dictionary<string, MsiPatchMetadataSymbol> patchMetadata, WixPatchIdSymbol patchIdSymbol, WindowsInstallerData mainTransform, MediaSymbol mediaSymbol, WixPatchBaselineSymbol baselineSymbol, out string productCode)
1093 + private WindowsInstallerData BuildPairedTransform(Dictionary<SummaryInformationType, SummaryInformationSymbol> summaryInfo, Dictionary<string, MsiPatchMetadataSymbol> patchMetadata, WixPatchSymbol patchIdSymbol, WindowsInstallerData mainTransform, MediaSymbol mediaSymbol, WixPatchBaselineSymbol baselineSymbol, out string productCode)
1094 {
1095 productCode = null;
1096
src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+71 -56
@@ -37,7 +37,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
37
38 this.CabbingThreadCount = context.CabbingThreadCount;
39 this.CabCachePath = context.CabCachePath;
40 - this.Codepage = context.Codepage;
40 this.DefaultCompressionLevel = context.DefaultCompressionLevel;
41 this.DelayedFields = context.DelayedFields;
42 this.ExpectedEmbeddedFiles = context.ExpectedEmbeddedFiles;
@@ -47,6 +46,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
46 this.OutputPath = context.OutputPath;
47 this.OutputPdbPath = context.PdbPath;
48 this.PdbType = context.PdbType;
49 + this.ResolvedCodepage = context.ResolvedCodepage;
50 + this.ResolvedSummaryInformationCodepage = context.ResolvedSummaryInformationCodepage;
51 + this.ResolvedLcid = context.ResolvedLcid;
52 this.SuppressLayout = context.SuppressLayout;
53
54 this.SubStorages = subStorages;
@@ -67,8 +69,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
69
70 private IPathResolver PathResolver { get; }
71
70 - private int Codepage { get; }
71 -
72 private int CabbingThreadCount { get; }
73
74 private string CabCachePath { get; }
@@ -95,6 +95,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind
95
96 private string OutputPdbPath { get; }
97
98 + private int? ResolvedCodepage { get; }
99 +
100 + private int? ResolvedSummaryInformationCodepage { get; }
101 +
102 + private int? ResolvedLcid { get; }
103 +
104 private bool SuppressAddingValidationRows { get; }
105
106 private bool SuppressLayout { get; }
@@ -111,21 +117,22 @@ namespace WixToolset.Core.WindowsInstaller.Bind
117
118 public IBindResult Execute()
119 {
114 - if (!this.Intermediate.HasLevel(Data.IntermediateLevels.Linked) && !this.Intermediate.HasLevel(Data.IntermediateLevels.Resolved))
120 + if (!this.Intermediate.HasLevel(Data.IntermediateLevels.Linked) || !this.Intermediate.HasLevel(Data.IntermediateLevels.Resolved))
121 {
122 this.Messaging.Write(ErrorMessages.IntermediatesMustBeResolved(this.Intermediate.Id));
123 }
124
125 var section = this.Intermediate.Sections.Single();
126
127 + var packageSymbol = (section.Type == SectionType.Product) ? this.GetSingleSymbol<WixPackageSymbol>(section) : null;
128 + var moduleSymbol = (section.Type == SectionType.Module) ? this.GetSingleSymbol<WixModuleSymbol>(section) : null;
129 + var patchSymbol = (section.Type == SectionType.Patch) ? this.GetSingleSymbol<WixPatchSymbol>(section) : null;
130 +
131 var fileTransfers = new List<IFileTransfer>();
132 var trackedFiles = new List<ITrackedFile>();
133
134 var containsMergeModules = false;
135
126 - // If there are any fields to resolve later, create the cache to populate during bind.
127 - var variableCache = this.DelayedFields.Any() ? new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) : null;
128 -
136 // Load standard tables, authored custom tables, and extension custom tables.
137 TableDefinitionCollection tableDefinitions;
138 {
@@ -135,7 +142,21 @@ namespace WixToolset.Core.WindowsInstaller.Bind
142 tableDefinitions = command.TableDefinitions;
143 }
144
138 - // Process the summary information table before the other tables.
145 + // Calculate codepage
146 + var codepage = this.CalculateCodepage(packageSymbol, moduleSymbol, patchSymbol);
147 +
148 + // Process properties and create the delayed variable cache if needed.
149 + Dictionary<string, string> variableCache = null;
150 + string productLanguage = null;
151 + {
152 + var command = new ProcessPropertiesCommand(section, packageSymbol, this.ResolvedLcid ?? 0, this.DelayedFields.Any(), this.WindowsInstallerBackendHelper);
153 + command.Execute();
154 +
155 + variableCache = command.DelayedVariablesCache;
156 + productLanguage = command.ProductLanguage;
157 + }
158 +
159 + // Process the summary information table after properties are processed.
160 bool compressed;
161 bool longNames;
162 int installerVersion;
@@ -144,7 +165,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
165 {
166 var branding = this.ServiceProvider.GetService<IWixBranding>();
167
147 - var command = new BindSummaryInfoCommand(section, this.WindowsInstallerBackendHelper, branding);
168 + var command = new BindSummaryInfoCommand(section, this.ResolvedSummaryInformationCodepage, productLanguage, this.WindowsInstallerBackendHelper, branding);
169 command.Execute();
170
171 compressed = command.Compressed;
@@ -154,49 +175,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
175 modularizationSuffix = command.ModularizationSuffix;
176 }
177
157 - // Add binder variables for all properties.
158 - if (SectionType.Product == section.Type || variableCache != null)
159 - {
160 - foreach (var propertyRow in section.Symbols.OfType<PropertySymbol>())
161 - {
162 - // Set the ProductCode if it is to be generated.
163 - if ("ProductCode".Equals(propertyRow.Id.Id, StringComparison.Ordinal) && "*".Equals(propertyRow.Value, StringComparison.Ordinal))
164 - {
165 - propertyRow.Value = this.WindowsInstallerBackendHelper.CreateGuid();
166 -
167 -#if TODO_PATCHING // Is this still necessary?
168 -
169 - // Update the target ProductCode in any instance transforms.
170 - foreach (SubStorage subStorage in this.Output.SubStorages)
171 - {
172 - Output subStorageOutput = subStorage.Data;
173 - if (OutputType.Transform != subStorageOutput.Type)
174 - {
175 - continue;
176 - }
177 -
178 - Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"];
179 - foreach (Row row in instanceSummaryInformationTable.Rows)
180 - {
181 - if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0))
182 - {
183 - row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value);
184 - break;
185 - }
186 - }
187 - }
188 -#endif
189 - }
190 -
191 - // Add the property name and value to the variableCache.
192 - if (variableCache != null)
193 - {
194 - var key = String.Concat("property.", propertyRow.Id.Id);
195 - variableCache[key] = propertyRow.Value;
196 - }
197 - }
198 - }
199 -
178 // Sequence all the actions.
179 {
180 var command = new SequenceActionsCommand(this.Messaging, section);
@@ -415,7 +393,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
393 // Time to create the WindowsInstallerData object. Try to put as much above here as possible, updating the IR is better.
394 WindowsInstallerData data;
395 {
418 - var command = new CreateWindowsInstallerDataFromIRCommand(this.Messaging, section, tableDefinitions, this.BackendExtensions, this.WindowsInstallerBackendHelper);
396 + var command = new CreateWindowsInstallerDataFromIRCommand(this.Messaging, section, tableDefinitions, codepage, this.BackendExtensions, this.WindowsInstallerBackendHelper);
397 data = command.Execute();
398 }
399
@@ -450,7 +428,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
428
429 if (SectionType.Patch == section.Type && this.DeltaBinaryPatch)
430 {
453 - var command = new CreateDeltaPatchesCommand(fileFacades, this.IntermediateFolder, section.Symbols.OfType<WixPatchIdSymbol>().FirstOrDefault());
431 + var command = new CreateDeltaPatchesCommand(fileFacades, this.IntermediateFolder, section.Symbols.OfType<WixPatchSymbol>().FirstOrDefault());
432 command.Execute();
433 }
434
@@ -508,7 +486,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
486 var trackMsi = this.WindowsInstallerBackendHelper.TrackFile(this.OutputPath, TrackedFileType.Final);
487 trackedFiles.Add(trackMsi);
488
511 - var command = new GenerateDatabaseCommand(this.Messaging, this.WindowsInstallerBackendHelper, this.FileSystemManager, data, trackMsi.Path, tableDefinitions, this.IntermediateFolder, this.Codepage, keepAddedColumns: false, this.SuppressAddingValidationRows, useSubdirectory: false);
489 + var command = new GenerateDatabaseCommand(this.Messaging, this.WindowsInstallerBackendHelper, this.FileSystemManager, data, trackMsi.Path, tableDefinitions, this.IntermediateFolder, keepAddedColumns: false, this.SuppressAddingValidationRows, useSubdirectory: false);
490 command.Execute();
491
492 trackedFiles.AddRange(command.GeneratedTemporaryFiles);
@@ -532,7 +510,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
510 if (this.Messaging.EncounteredError)
511 {
512 return null;
535 - }
513 + }
514
515 // Validate the output if there are CUBe files and we're not explicitly suppressing validation.
516 if (this.CubeFiles != null && !this.SuppressValidation)
@@ -575,6 +553,43 @@ namespace WixToolset.Core.WindowsInstaller.Bind
553 return result;
554 }
555
556 + private int CalculateCodepage(WixPackageSymbol packageSymbol, WixModuleSymbol moduleSymbol, WixPatchSymbol patchSymbol)
557 + {
558 + var codepage = packageSymbol?.Codepage ?? moduleSymbol?.Codepage ?? patchSymbol?.Codepage;
559 +
560 + if (String.IsNullOrEmpty(codepage))
561 + {
562 + codepage = this.ResolvedCodepage?.ToString() ?? "65001";
563 +
564 + if (packageSymbol != null)
565 + {
566 + packageSymbol.Codepage = codepage;
567 + }
568 + else if (moduleSymbol != null)
569 + {
570 + moduleSymbol.Codepage = codepage;
571 + }
572 + else if (patchSymbol != null)
573 + {
574 + patchSymbol.Codepage = codepage;
575 + }
576 + }
577 +
578 + return this.WindowsInstallerBackendHelper.GetValidCodePage(codepage);
579 + }
580 +
581 + private T GetSingleSymbol<T>(IntermediateSection section) where T : IntermediateSymbol
582 + {
583 + var symbols = section.Symbols.OfType<T>().ToList();
584 +
585 + if (1 != symbols.Count)
586 + {
587 + throw new WixException(ErrorMessages.MissingBundleInformation(nameof(T)));
588 + }
589 +
590 + return symbols[0];
591 + }
592 +
593 private WixOutput CreateWixout(List<ITrackedFile> trackedFiles, Intermediate intermediate, WindowsInstallerData data)
594 {
595 WixOutput wixout;
src/WixToolset.Core.WindowsInstaller/Bind/BindSummaryInfoCommand.cs
+46 -15
@@ -14,15 +14,21 @@ namespace WixToolset.Core.WindowsInstaller.Bind
14 /// </summary>
15 internal class BindSummaryInfoCommand
16 {
17 - public BindSummaryInfoCommand(IntermediateSection section, IBackendHelper backendHelper, IWixBranding branding)
17 + public BindSummaryInfoCommand(IntermediateSection section, int? summaryInformationCodepage, string productLanguage, IBackendHelper backendHelper, IWixBranding branding)
18 {
19 this.Section = section;
20 + this.SummaryInformationCodepage = summaryInformationCodepage;
21 + this.ProductLanguage = productLanguage;
22 this.BackendHelper = backendHelper;
23 this.Branding = branding;
24 }
25
26 private IntermediateSection Section { get; }
27
28 + private int? SummaryInformationCodepage { get; }
29 +
30 + private string ProductLanguage { get; }
31 +
32 private IBackendHelper BackendHelper { get; }
33
34 private IWixBranding Branding { get; }
@@ -53,6 +59,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
59 this.InstallerVersion = 0;
60 this.ModularizationSuffix = null;
61
62 + SummaryInformationSymbol summaryInformationCodepageSymbol = null;
63 + SummaryInformationSymbol platformAndLanguageSymbol = null;
64 var foundCreateDateTime = false;
65 var foundLastSaveDataTime = false;
66 var foundCreatingApplication = false;
@@ -64,20 +72,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
72 switch (summaryInformationSymbol.PropertyId)
73 {
74 case SummaryInformationType.Codepage: // PID_CODEPAGE
67 - // make sure the code page is an int and not a web name or null
68 - var codepage = summaryInformationSymbol.Value;
69 -
70 - if (String.IsNullOrEmpty(codepage))
71 - {
72 - codepage = "0";
73 - }
74 - else
75 - {
76 - summaryInformationSymbol.Value = this.BackendHelper.GetValidCodePage(codepage, false, false, summaryInformationSymbol.SourceLineNumbers).ToString(CultureInfo.InvariantCulture);
77 - }
75 + summaryInformationCodepageSymbol = summaryInformationSymbol;
76 break;
77 +
78 case SummaryInformationType.PlatformAndLanguage:
80 - this.Platform = GetPlatformFromSummaryInformation(summaryInformationSymbol.Value);
79 + platformAndLanguageSymbol = summaryInformationSymbol;
80 break;
81
82 case SummaryInformationType.PackageCode: // PID_REVNUMBER
@@ -117,7 +116,31 @@ namespace WixToolset.Core.WindowsInstaller.Bind
116 }
117 }
118
120 - // set the revision number (package/patch code) if it should be automatically generated
119 + // Ensure the codepage is set properly.
120 + if (summaryInformationCodepageSymbol == null)
121 + {
122 + summaryInformationCodepageSymbol = this.Section.AddSymbol(new SummaryInformationSymbol(null)
123 + {
124 + PropertyId = SummaryInformationType.Codepage
125 + });
126 + }
127 +
128 + var codepage = summaryInformationCodepageSymbol.Value;
129 +
130 + if (String.IsNullOrEmpty(codepage))
131 + {
132 + codepage = this.SummaryInformationCodepage?.ToString(CultureInfo.InvariantCulture) ?? "1252";
133 + }
134 +
135 + summaryInformationCodepageSymbol.Value = this.BackendHelper.GetValidCodePage(codepage, onlyAnsi: true).ToString(CultureInfo.InvariantCulture);
136 +
137 + // Ensure the language is set properly and figure out what platform we are targeting.
138 + if (platformAndLanguageSymbol != null)
139 + {
140 + this.Platform = EnsureLanguageAndGetPlatformFromSummaryInformation(platformAndLanguageSymbol, this.ProductLanguage);
141 + }
142 +
143 + // Set the revision number (package/patch code) if it should be automatically generated.
144 if (!foundPackageCode)
145 {
146 this.Section.AddSymbol(new SummaryInformationSymbol(null)
@@ -158,11 +181,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind
181 }
182 }
183
161 - private static Platform GetPlatformFromSummaryInformation(string value)
184 + private static Platform EnsureLanguageAndGetPlatformFromSummaryInformation(SummaryInformationSymbol symbol, string language)
185 {
186 + var value = symbol.Value;
187 var separatorIndex = value.IndexOf(';');
188 var platformValue = separatorIndex > 0 ? value.Substring(0, separatorIndex) : value;
189
190 + // If the language was provided and there was language value after the separator
191 + // (or the separator was absent) then use the provided language.
192 + if (!String.IsNullOrEmpty(language) && (separatorIndex < 0 || separatorIndex + 1 == value.Length))
193 + {
194 + symbol.Value = platformValue + ';' + language;
195 + }
196 +
197 switch (platformValue)
198 {
199 case "x64":
src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
+1 -1
@@ -438,7 +438,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
438
439 private void GenerateDatabase(WindowsInstallerData output, string outputPath, bool keepAddedColumns)
440 {
441 - var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, output, outputPath, this.TableDefinitions, this.IntermediateFolder, codepage: -1, keepAddedColumns, suppressAddingValidationRows: true, useSubdirectory: true);
441 + var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, output, outputPath, this.TableDefinitions, this.IntermediateFolder, keepAddedColumns, suppressAddingValidationRows: true, useSubdirectory: true);
442 command.Execute();
443 }
444 }
src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs
+2 -2
@@ -15,7 +15,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
15 /// </summary>
16 internal class CreateDeltaPatchesCommand
17 {
18 - public CreateDeltaPatchesCommand(List<IFileFacade> fileFacades, string intermediateFolder, WixPatchIdSymbol wixPatchId)
18 + public CreateDeltaPatchesCommand(List<IFileFacade> fileFacades, string intermediateFolder, WixPatchSymbol wixPatchId)
19 {
20 this.FileFacades = fileFacades;
21 this.IntermediateFolder = intermediateFolder;
@@ -24,7 +24,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
24
25 private IEnumerable<IFileFacade> FileFacades { get; }
26
27 - private WixPatchIdSymbol WixPatchId { get; }
27 + private WixPatchSymbol WixPatchId { get; }
28
29 private string IntermediateFolder { get; }
30
src/WixToolset.Core.WindowsInstaller/Bind/CreateIdtFileCommand.cs
+25 -17
@@ -36,23 +36,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
36 public void Execute()
37 {
38 // write out the table to an IDT file
39 - Encoding encoding;
40 -
41 - // If UTF8 encoding, use the UTF8-specific constructor to avoid writing
42 - // the byte order mark at the beginning of the file
43 - if (this.Codepage == Encoding.UTF8.CodePage)
44 - {
45 - encoding = new UTF8Encoding(false, true);
46 - }
47 - else
48 - {
49 - if (this.Codepage == 0)
50 - {
51 - this.Codepage = Encoding.ASCII.CodePage;
52 - }
53 -
54 - encoding = Encoding.GetEncoding(this.Codepage, new EncoderExceptionFallback(), new DecoderExceptionFallback());
55 - }
39 + var encoding = GetCodepageEncoding(this.Codepage);
40
41 this.IdtPath = Path.Combine(this.IntermediateFolder, String.Concat(this.Table.Name, ".idt"));
42
@@ -209,6 +193,30 @@ namespace WixToolset.Core.WindowsInstaller.Bind
193 .Replace('\n', '\x19');
194 }
195
196 + private static Encoding GetCodepageEncoding(int codepage)
197 + {
198 + Encoding encoding;
199 +
200 + // If UTF8 encoding, use the UTF8-specific constructor to avoid writing
201 + // the byte order mark at the beginning of the file
202 + if (codepage == Encoding.UTF8.CodePage)
203 + {
204 + encoding = new UTF8Encoding(false, true);
205 + }
206 + else
207 + {
208 + if (codepage == 0)
209 + {
210 + codepage = Encoding.ASCII.CodePage;
211 + }
212 +
213 + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
214 +
215 + encoding = Encoding.GetEncoding(codepage, new EncoderExceptionFallback(), new DecoderExceptionFallback());
216 + }
217 +
218 + return encoding;
219 + }
220
221 /// <summary>
222 /// Gets the type of the column in IDT format.
src/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
+29 -3
@@ -18,11 +18,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind
18
19 internal class CreateWindowsInstallerDataFromIRCommand
20 {
21 - public CreateWindowsInstallerDataFromIRCommand(IMessaging messaging, IntermediateSection section, TableDefinitionCollection tableDefinitions, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtensions, IWindowsInstallerBackendHelper backendHelper)
21 + public CreateWindowsInstallerDataFromIRCommand(IMessaging messaging, IntermediateSection section, TableDefinitionCollection tableDefinitions, int codepage, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtensions, IWindowsInstallerBackendHelper backendHelper)
22 {
23 this.Messaging = messaging;
24 this.Section = section;
25 this.TableDefinitions = tableDefinitions;
26 + this.Codepage = codepage;
27 this.BackendExtensions = backendExtensions;
28 this.BackendHelper = backendHelper;
29 this.GeneratedShortNames = new Dictionary<string, List<FileSymbol>>();
@@ -36,6 +37,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
37
38 private TableDefinitionCollection TableDefinitions { get; }
39
40 + private int Codepage { get; }
41 +
42 private IntermediateSection Section { get; }
43
44 private Dictionary<string, List<FileSymbol>> GeneratedShortNames { get; }
@@ -46,7 +49,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
49 {
50 this.Data = new WindowsInstallerData(this.Section.Symbols.First().SourceLineNumbers)
51 {
49 - Codepage = this.Section.Codepage,
52 + Codepage = this.Codepage,
53 Type = SectionTypeToOutputType(this.Section.Type)
54 };
55
@@ -219,6 +222,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
222 this.AddWixEnsureTableSymbol((WixEnsureTableSymbol)symbol);
223 break;
224
225 + case SymbolDefinitionType.WixPackage:
226 + this.AddWixPackageSymbol((WixPackageSymbol)symbol);
227 + break;
228 +
229 // Symbols used internally and are not added to the output.
230 case SymbolDefinitionType.WixBuildInfo:
231 case SymbolDefinitionType.WixBindUpdatedFiles:
@@ -237,7 +244,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
244 case SymbolDefinitionType.WixOrdering:
245 case SymbolDefinitionType.WixPatchBaseline:
246 case SymbolDefinitionType.WixPatchFamilyGroup:
240 - case SymbolDefinitionType.WixPatchId:
247 + case SymbolDefinitionType.WixPatch:
248 case SymbolDefinitionType.WixPatchRef:
249 case SymbolDefinitionType.WixPatchTarget:
250 case SymbolDefinitionType.WixProperty:
@@ -1214,6 +1221,25 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1221 this.Data.EnsureTable(tableDefinition);
1222 }
1223
1224 + private void AddWixPackageSymbol(WixPackageSymbol symbol)
1225 + {
1226 + // TODO: Remove the following from the compiler and do it here instead.
1227 + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "Manufacturer"), manufacturer, false, false, false, true);
1228 + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductCode"), productCode, false, false, false, true);
1229 + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductLanguage"), productLanguage, false, false, false, true);
1230 + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductName"), this.activeName, false, false, false, true);
1231 + //this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductVersion"), version, false, false, false, true);
1232 + //if (null != upgradeCode)
1233 + //{
1234 + // this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "UpgradeCode"), upgradeCode, false, false, false, true);
1235 + //}
1236 +
1237 + //if (isPerMachine)
1238 + //{
1239 + // this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ALLUSERS"), "1", false, false, false, false);
1240 + //}
1241 + }
1242 +
1243 private bool AddSymbolFromExtension(IntermediateSymbol symbol)
1244 {
1245 foreach (var extension in this.BackendExtensions)
src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs
+1 -10
@@ -18,7 +18,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
18 {
19 private const string IdtsSubFolder = "_idts";
20
21 - public GenerateDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, FileSystemManager fileSystemManager, WindowsInstallerData data, string outputPath, TableDefinitionCollection tableDefinitions, string intermediateFolder, int codepage, bool keepAddedColumns, bool suppressAddingValidationRows, bool useSubdirectory)
21 + public GenerateDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, FileSystemManager fileSystemManager, WindowsInstallerData data, string outputPath, TableDefinitionCollection tableDefinitions, string intermediateFolder, bool keepAddedColumns, bool suppressAddingValidationRows, bool useSubdirectory)
22 {
23 this.Messaging = messaging;
24 this.BackendHelper = backendHelper;
@@ -27,14 +27,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
27 this.OutputPath = outputPath;
28 this.TableDefinitions = tableDefinitions;
29 this.IntermediateFolder = intermediateFolder;
30 - this.Codepage = codepage;
30 this.KeepAddedColumns = keepAddedColumns;
31 this.SuppressAddingValidationRows = suppressAddingValidationRows;
32 this.UseSubDirectory = useSubdirectory;
33 }
34
36 - private int Codepage { get; }
37 -
35 private IBackendHelper BackendHelper { get; }
36
37 private FileSystemManager FileSystemManager { get; }
@@ -88,12 +85,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
85 type |= OpenDatabase.OpenPatchFile;
86 }
87
91 - // Localize the codepage if a value was specified directly.
92 - if (-1 != this.Codepage)
93 - {
94 - this.Data.Codepage = this.Codepage;
95 - }
96 -
88 try
89 {
90 Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath));
src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs
-1
@@ -9,7 +9,6 @@ namespace WixToolset.Core.WindowsInstaller
9 using WixToolset.Data;
10 using WixToolset.Data.Symbols;
11 using WixToolset.Data.WindowsInstaller;
12 - using WixToolset.Data.WindowsInstaller.Rows;
12 using WixToolset.Extensibility.Services;
13
14 /// <summary>
src/WixToolset.Core.WindowsInstaller/Bind/ProcessPropertiesCommand.cs new
+101
@@ -0,0 +1,101 @@
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 +namespace WixToolset.Core.WindowsInstaller.Bind
4 +{
5 + using System;
6 + using System.Collections.Generic;
7 + using System.Linq;
8 + using WixToolset.Data;
9 + using WixToolset.Data.Symbols;
10 + using WixToolset.Extensibility.Services;
11 +
12 + internal class ProcessPropertiesCommand
13 + {
14 + public ProcessPropertiesCommand(IntermediateSection section, WixPackageSymbol packageSymbol, int fallbackLcid, bool populateDelayedVariables, IBackendHelper backendHelper)
15 + {
16 + this.Section = section;
17 + this.PackageSymbol = packageSymbol;
18 + this.FallbackLcid = fallbackLcid;
19 + this.PopulateDelayedVariables = populateDelayedVariables;
20 + this.BackendHelper = backendHelper;
21 + }
22 +
23 + private IntermediateSection Section { get; }
24 +
25 + private WixPackageSymbol PackageSymbol { get; }
26 +
27 + private int FallbackLcid { get; }
28 +
29 + private bool PopulateDelayedVariables { get; }
30 +
31 + private IBackendHelper BackendHelper { get; }
32 +
33 + public Dictionary<string, string> DelayedVariablesCache { get; private set; }
34 +
35 + public string ProductLanguage { get; private set; }
36 +
37 + public void Execute()
38 + {
39 + PropertySymbol languageSymbol = null;
40 + var variableCache = this.PopulateDelayedVariables ? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) : null;
41 +
42 + if (SectionType.Product == this.Section.Type || variableCache != null)
43 + {
44 + foreach (var propertySymbol in this.Section.Symbols.OfType<PropertySymbol>())
45 + {
46 + // Set the ProductCode if it is to be generated.
47 + if ("ProductCode" == propertySymbol.Id.Id && "*".Equals(propertySymbol.Value, StringComparison.Ordinal))
48 + {
49 + propertySymbol.Value = this.BackendHelper.CreateGuid();
50 +
51 +#if TODO_PATCHING // Is this still necessary?
52 + // Update the target ProductCode in any instance transforms.
53 + foreach (SubStorage subStorage in this.Output.SubStorages)
54 + {
55 + Output subStorageOutput = subStorage.Data;
56 + if (OutputType.Transform != subStorageOutput.Type)
57 + {
58 + continue;
59 + }
60 +
61 + Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"];
62 + foreach (Row row in instanceSummaryInformationTable.Rows)
63 + {
64 + if ((int)SummaryInformation.Transform.ProductCodes == row.FieldAsInteger(0))
65 + {
66 + row[1] = row.FieldAsString(1).Replace("*", propertyRow.Value);
67 + break;
68 + }
69 + }
70 + }
71 +#endif
72 + }
73 + else if ("ProductLanguage" == propertySymbol.Id.Id)
74 + {
75 + languageSymbol = propertySymbol;
76 + }
77 +
78 + // Add the property name and value to the variableCache.
79 + if (variableCache != null)
80 + {
81 + variableCache[$"property.{propertySymbol.Id.Id}"] = propertySymbol.Value;
82 + }
83 + }
84 +
85 + if (this.Section.Type == SectionType.Product && String.IsNullOrEmpty(languageSymbol?.Value))
86 + {
87 + if (languageSymbol == null)
88 + {
89 + languageSymbol = this.Section.AddSymbol(new PropertySymbol(this.PackageSymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, "ProductLanguage")));
90 + }
91 +
92 + this.PackageSymbol.Language = this.FallbackLcid.ToString();
93 + languageSymbol.Value = this.FallbackLcid.ToString();
94 + }
95 + }
96 +
97 + this.DelayedVariablesCache = variableCache;
98 + this.ProductLanguage = languageSymbol?.Value;
99 + }
100 + }
101 +}
src/WixToolset.Core.WindowsInstaller/Unbind/UnbindTranformCommand.cs
+1 -1
@@ -302,7 +302,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
302
303 private void GenerateDatabase(WindowsInstallerData output, string databaseFile)
304 {
305 - var command = new GenerateDatabaseCommand(this.Messaging, null, null, output, databaseFile, this.TableDefinitions, this.IntermediateFolder, codepage: -1, keepAddedColumns: true, suppressAddingValidationRows: true, useSubdirectory: false);
305 + var command = new GenerateDatabaseCommand(this.Messaging, null, null, output, databaseFile, this.TableDefinitions, this.IntermediateFolder, keepAddedColumns: true, suppressAddingValidationRows: true, useSubdirectory: false);
306 command.Execute();
307 }
308 }
src/WixToolset.Core.WindowsInstaller/WixToolset.Core.WindowsInstaller.csproj
+1
@@ -20,6 +20,7 @@
20
21 <ItemGroup>
22 <PackageReference Include="System.Reflection.Metadata" Version="1.6.0" />
23 + <PackageReference Include="System.Text.Encoding.CodePages" Version="4.6.0" />
24 </ItemGroup>
25
26 <ItemGroup>
src/WixToolset.Core/BindContext.cs
+6 -2
@@ -26,8 +26,6 @@ namespace WixToolset.Core
26
27 public string CabCachePath { get; set; }
28
29 - public int Codepage { get; set; }
30 -
29 public CompressionLevel? DefaultCompressionLevel { get; set; }
30
31 public IEnumerable<IDelayedField> DelayedFields { get; set; }
@@ -50,6 +48,12 @@ namespace WixToolset.Core
48
49 public string PdbPath { get; set; }
50
51 + public int? ResolvedCodepage { get; set; }
52 +
53 + public int? ResolvedSummaryInformationCodepage { get; set; }
54 +
55 + public int? ResolvedLcid { get; set; }
56 +
57 public IEnumerable<string> SuppressIces { get; set; }
58
59 public bool SuppressValidation { get; set; }
src/WixToolset.Core/CommandLine/BuildCommand.cs
+3 -1
@@ -338,7 +338,9 @@ namespace WixToolset.Core.CommandLine
338 var context = this.ServiceProvider.GetService<IBindContext>();
339 //context.CabbingThreadCount = this.CabbingThreadCount;
340 context.CabCachePath = cabCachePath;
341 - context.Codepage = resolveResult.Codepage;
341 + context.ResolvedCodepage = resolveResult.Codepage;
342 + context.ResolvedSummaryInformationCodepage = resolveResult.SummaryInformationCodepage;
343 + context.ResolvedLcid = resolveResult.PackageLcid;
344 context.DefaultCompressionLevel = this.DefaultCompressionLevel;
345 context.DelayedFields = resolveResult.DelayedFields;
346 context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles;
src/WixToolset.Core/Compiler.cs
+2 -2
@@ -384,7 +384,7 @@ namespace WixToolset.Core
384 {
385 var id = String.Concat(this.Core.ActiveSection.Id, ".", propertyId.Id);
386
387 - section = this.Core.CreateSection(id, SectionType.Fragment, this.Core.ActiveSection.Codepage, this.Context.CompilationId);
387 + section = this.Core.CreateSection(id, SectionType.Fragment, this.Context.CompilationId);
388
389 // Reference the property in the active section.
390 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Property, propertyId.Id);
@@ -6159,7 +6159,7 @@ namespace WixToolset.Core
6159
6160 // NOTE: Id is not required for Fragments, this is a departure from the normal run of the mill processing.
6161
6162 - this.Core.CreateActiveSection(id?.Id, SectionType.Fragment, 0, this.Context.CompilationId);
6162 + this.Core.CreateActiveSection(id?.Id, SectionType.Fragment, this.Context.CompilationId);
6163
6164 var featureDisplay = 0;
6165 foreach (var child in node.Elements())
src/WixToolset.Core/CompilerCore.cs
+8 -10
@@ -680,7 +680,7 @@ namespace WixToolset.Core
680
681 Debug.Assert(minimum > CompilerConstants.IntegerNotSet && minimum > CompilerConstants.IllegalInteger, "The legal values for this attribute collide with at least one sentinel used during parsing.");
682
683 - string value = this.GetAttributeValue(sourceLineNumbers, attribute);
683 + var value = this.GetAttributeValue(sourceLineNumbers, attribute);
684
685 if (0 < value.Length)
686 {
@@ -692,7 +692,7 @@ namespace WixToolset.Core
692 {
693 try
694 {
695 - int integer = Convert.ToInt32(value, CultureInfo.InvariantCulture.NumberFormat);
695 + var integer = Convert.ToInt32(value, CultureInfo.InvariantCulture.NumberFormat);
696
697 if (CompilerConstants.IntegerNotSet == integer || CompilerConstants.IllegalInteger == integer)
698 {
@@ -1036,12 +1036,11 @@ namespace WixToolset.Core
1036 /// </summary>
1037 /// <param name="id">Unique identifier for the section.</param>
1038 /// <param name="type">Type of section to create.</param>
1039 - /// <param name="codepage">Codepage for the resulting database for this ection.</param>
1040 - /// <param name="compilationId"></param>
1039 + /// <param name="compilationId">Unique identifier for the compilation.</param>
1040 /// <returns>New section.</returns>
1042 - internal IntermediateSection CreateActiveSection(string id, SectionType type, int codepage, string compilationId)
1041 + internal IntermediateSection CreateActiveSection(string id, SectionType type, string compilationId)
1042 {
1044 - this.ActiveSection = this.CreateSection(id, type, codepage, compilationId);
1043 + this.ActiveSection = this.CreateSection(id, type, compilationId);
1044
1045 this.activeSectionCachedInlinedDirectoryIds = new Dictionary<string, string>();
1046 this.activeSectionSimpleReferences = new HashSet<string>();
@@ -1054,12 +1053,11 @@ namespace WixToolset.Core
1053 /// </summary>
1054 /// <param name="id">Unique identifier for the section.</param>
1055 /// <param name="type">Type of section to create.</param>
1057 - /// <param name="codepage">Codepage for the resulting database for this ection.</param>
1058 - /// <param name="compilationId"></param>
1056 + /// <param name="compilationId">Unique identifier for the compilation.</param>
1057 /// <returns>New section.</returns>
1060 - internal IntermediateSection CreateSection(string id, SectionType type, int codepage, string compilationId)
1058 + internal IntermediateSection CreateSection(string id, SectionType type, string compilationId)
1059 {
1062 - var section = new IntermediateSection(id, type, codepage, compilationId);
1060 + var section = new IntermediateSection(id, type, compilationId);
1061
1062 this.intermediate.Sections.Add(section);
1063
src/WixToolset.Core/Compiler_Bundle.cs
+1 -1
@@ -259,7 +259,7 @@ namespace WixToolset.Core
259 }
260
261 this.activeName = String.IsNullOrEmpty(name) ? Common.GenerateGuid() : name;
262 - this.Core.CreateActiveSection(this.activeName, SectionType.Bundle, 0, this.Context.CompilationId);
262 + this.Core.CreateActiveSection(this.activeName, SectionType.Bundle, this.Context.CompilationId);
263
264 // Now that the active section is initialized, process only extension attributes and the special ProviderKey attribute.
265 foreach (var attrib in node.Attributes())
src/WixToolset.Core/Compiler_Module.cs
+5 -15
@@ -104,7 +104,7 @@ namespace WixToolset.Core
104 try
105 {
106 this.compilingModule = true; // notice that we are actually building a Merge Module here
107 - this.Core.CreateActiveSection(this.activeName, SectionType.Module, codepage, this.Context.CompilationId);
107 + this.Core.CreateActiveSection(this.activeName, SectionType.Module, this.Context.CompilationId);
108
109 foreach (var child in node.Elements())
110 {
@@ -232,15 +232,6 @@ namespace WixToolset.Core
232
233 if (!this.Core.EncounteredError)
234 {
235 - if (!setCodepage)
236 - {
237 - this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
238 - {
239 - PropertyId = SummaryInformationType.Codepage,
240 - Value = "1252"
241 - });
242 - }
243 -
235 if (!setPackageName)
236 {
237 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
@@ -259,21 +250,20 @@ namespace WixToolset.Core
250 });
251 }
252
262 - var symbol = this.Core.AddSymbol(new ModuleSignatureSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, this.activeName, this.activeLanguage))
253 + var symbol = this.Core.AddSymbol(new WixModuleSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, this.activeName, this.activeLanguage))
254 {
264 - ModuleID = this.activeName,
255 + ModuleId = this.activeName,
256 + Language = this.activeLanguage,
257 Version = version
258 });
259
268 - symbol.Set((int)ModuleSignatureSymbolFields.Language, this.activeLanguage);
269 -
260 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
261 {
262 PropertyId = SummaryInformationType.PackageCode,
263 Value = moduleId
264 });
265
276 - this.ValidateAndAddCommonSummaryInformationSymbols(sourceLineNumbers, msiVersion, platform);
266 + this.ValidateAndAddCommonSummaryInformationSymbols(sourceLineNumbers, msiVersion, platform, this.activeLanguage);
267 }
268 }
269 finally
src/WixToolset.Core/Compiler_Package.cs
+21 -25
@@ -5,7 +5,6 @@ namespace WixToolset.Core
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 - using System.Diagnostics.CodeAnalysis;
8 using System.Globalization;
9 using System.IO;
10 using System.Xml.Linq;
@@ -28,10 +27,10 @@ namespace WixToolset.Core
27 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
28 var compressed = YesNoDefaultType.Default;
29 var sourceBits = 0;
31 - var codepage = 65001;
30 + string codepage = null;
31 var productCode = "*";
32 + string productLanguage = null;
33 var isPerMachine = true;
34 - string installScope = null;
34 string upgradeCode = null;
35 string manufacturer = null;
36 string version = null;
@@ -53,7 +52,7 @@ namespace WixToolset.Core
52 switch (attrib.Name.LocalName)
53 {
54 case "Codepage":
56 - codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib);
55 + codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib);
56 break;
57 case "Compressed":
58 compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
@@ -62,7 +61,7 @@ namespace WixToolset.Core
61 msiVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
62 break;
63 case "Language":
65 - this.activeLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
64 + productLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
65 break;
66 case "Manufacturer":
67 manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters);
@@ -82,7 +81,7 @@ namespace WixToolset.Core
81 productCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true);
82 break;
83 case "Scope":
85 - installScope = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
84 + var installScope = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
85 switch (installScope)
86 {
87 case "perMachine":
@@ -129,11 +128,6 @@ namespace WixToolset.Core
128 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
129 }
130
132 - if (null == this.activeLanguage)
133 - {
134 - this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language"));
135 - }
136 -
131 if (null == manufacturer)
132 {
133 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer"));
@@ -171,11 +165,11 @@ namespace WixToolset.Core
165 try
166 {
167 this.compilingProduct = true;
174 - this.Core.CreateActiveSection(productCode, SectionType.Product, codepage, this.Context.CompilationId);
168 + this.Core.CreateActiveSection(productCode, SectionType.Product, this.Context.CompilationId);
169
170 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "Manufacturer"), manufacturer, false, false, false, true);
171 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductCode"), productCode, false, false, false, true);
178 - this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductLanguage"), this.activeLanguage, false, false, false, true);
172 + this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductLanguage"), productLanguage, false, false, false, true);
173 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductName"), this.activeName, false, false, false, true);
174 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductVersion"), version, false, false, false, true);
175 if (null != upgradeCode)
@@ -188,7 +182,7 @@ namespace WixToolset.Core
182 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ALLUSERS"), "1", false, false, false, false);
183 }
184
191 - this.ValidateAndAddCommonSummaryInformationSymbols(sourceLineNumbers, msiVersion, platform);
185 + this.ValidateAndAddCommonSummaryInformationSymbols(sourceLineNumbers, msiVersion, platform, productLanguage);
186
187 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
188 {
@@ -198,7 +192,7 @@ namespace WixToolset.Core
192
193 var contextValues = new Dictionary<string, string>
194 {
201 - ["ProductLanguage"] = this.activeLanguage,
195 + ["ProductLanguage"] = productLanguage,
196 ["ProductVersion"] = version,
197 ["UpgradeCode"] = upgradeCode
198 };
@@ -360,14 +354,17 @@ namespace WixToolset.Core
354
355 if (!this.Core.EncounteredError)
356 {
363 - if (!isCodepageSet)
357 + this.Core.AddSymbol(new WixPackageSymbol(sourceLineNumbers)
358 {
365 - this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
366 - {
367 - PropertyId = SummaryInformationType.Codepage,
368 - Value = "1252"
369 - });
370 - }
359 + PackageId = productCode,
360 + UpgradeCode = upgradeCode,
361 + Name = this.activeName,
362 + Language = productLanguage,
363 + Version = version,
364 + Manufacturer = manufacturer,
365 + Attributes = isPerMachine ? WixPackageAttributes.PerMachine : WixPackageAttributes.None,
366 + Codepage = codepage,
367 + });
368
369 if (!isPackageNameSet)
370 {
@@ -435,7 +432,7 @@ namespace WixToolset.Core
432 }
433 }
434
438 - private void ValidateAndAddCommonSummaryInformationSymbols(SourceLineNumber sourceLineNumbers, int msiVersion, string platform)
435 + private void ValidateAndAddCommonSummaryInformationSymbols(SourceLineNumber sourceLineNumbers, int msiVersion, string platform, string language)
436 {
437 if (String.Equals(platform, "X64", StringComparison.OrdinalIgnoreCase) && 200 > msiVersion)
438 {
@@ -464,7 +461,7 @@ namespace WixToolset.Core
461 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
462 {
463 PropertyId = SummaryInformationType.PlatformAndLanguage,
467 - Value = String.Format(CultureInfo.InvariantCulture, "{0};{1}", platform, this.activeLanguage)
464 + Value = $"{platform};{language}"
465 });
466
467 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
@@ -478,7 +475,6 @@ namespace WixToolset.Core
475 PropertyId = SummaryInformationType.Security,
476 Value = "2"
477 });
481 -
478 }
479
480 /// <summary>
src/WixToolset.Core/Compiler_Patch.cs
+5 -4
@@ -24,7 +24,7 @@ namespace WixToolset.Core
24 {
25 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
26 string patchId = null;
27 - var codepage = 0;
27 + string codepage = null;
28 ////bool versionMismatches = false;
29 ////bool productMismatches = false;
30 var allowRemoval = false;
@@ -53,7 +53,7 @@ namespace WixToolset.Core
53 patchId = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true);
54 break;
55 case "Codepage":
56 - codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib);
56 + codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib);
57 break;
58 case "AllowMajorVersionMismatches":
59 ////versionMismatches = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib));
@@ -149,7 +149,7 @@ namespace WixToolset.Core
149 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer"));
150 }
151
152 - this.Core.CreateActiveSection(this.activeName, SectionType.Patch, codepage, this.Context.CompilationId);
152 + this.Core.CreateActiveSection(this.activeName, SectionType.Patch, this.Context.CompilationId);
153
154 foreach (var child in node.Elements())
155 {
@@ -197,8 +197,9 @@ namespace WixToolset.Core
197
198 if (!this.Core.EncounteredError)
199 {
200 - this.Core.AddSymbol(new WixPatchIdSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, patchId))
200 + this.Core.AddSymbol(new WixPatchSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, patchId))
201 {
202 + Codepage = codepage,
203 ClientPatchId = clientPatchId,
204 OptimizePatchSizeForLargeFiles = optimizePatchSizeForLargeFiles,
205 ApiPatchingSymbolFlags = apiPatchingSymbolFlags,
src/WixToolset.Core/Compiler_PatchCreation.cs
+1 -1
@@ -82,7 +82,7 @@ namespace WixToolset.Core
82 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
83 }
84
85 - this.Core.CreateActiveSection(this.activeName, SectionType.PatchCreation, codepage, this.Context.CompilationId);
85 + this.Core.CreateActiveSection(this.activeName, SectionType.PatchCreation, this.Context.CompilationId);
86
87 foreach (var child in node.Elements())
88 {
src/WixToolset.Core/IResolver.cs
+8 -1
@@ -4,9 +4,16 @@ namespace WixToolset.Core
4 {
5 using WixToolset.Extensibility.Data;
6
7 -#pragma warning disable 1591 // TODO: add documentation
7 + /// <summary>
8 + /// Resolves localization and bind variables.
9 + /// </summary>
10 public interface IResolver
11 {
12 + /// <summary>
13 + /// Resolve localization and bind variables.
14 + /// </summary>
15 + /// <param name="context">Resolve context.</param>
16 + /// <returns>Resolve result.</returns>
17 IResolveResult Resolve(IResolveContext context);
18 }
19 }
src/WixToolset.Core/Link/CollateLocalizationsCommand.cs
+2 -2
@@ -1,4 +1,4 @@
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.
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 namespace WixToolset.Core.Link
4 {
@@ -65,7 +65,7 @@ namespace WixToolset.Core.Link
65 }
66 }
67
68 - return new Localization(existingLocalization.Codepage, existingLocalization.Culture, variables, controls);
68 + return new Localization(existingLocalization.Codepage ?? localization.Codepage, existingLocalization.SummaryInformationCodepage ?? localization.SummaryInformationCodepage, existingLocalization.Culture, variables, controls);
69 }
70 }
71 }
src/WixToolset.Core/Linker.cs
+1 -1
@@ -180,7 +180,7 @@ namespace WixToolset.Core
180
181 // Create a new section to hold the linked content. Start with the entry section's
182 // metadata.
183 - var resolvedSection = new IntermediateSection(find.EntrySection.Id, find.EntrySection.Type, find.EntrySection.Codepage);
183 + var resolvedSection = new IntermediateSection(find.EntrySection.Id, find.EntrySection.Type);
184
185 var sectionCount = 0;
186
src/WixToolset.Core/LocalizationParser.cs
+6 -14
@@ -86,7 +86,8 @@ namespace WixToolset.Core
86 private static Localization ParseWixLocalizationElement(IMessaging messaging, XElement node)
87 {
88 var sourceLineNumbers = SourceLineNumber.CreateFromXObject(node);
89 - var codepage = -1;
89 + int? codepage = null;
90 + int? summaryInformationCodepage = null;
91 string culture = null;
92
93 foreach (var attrib in node.Attributes())
@@ -98,6 +99,9 @@ namespace WixToolset.Core
99 case "Codepage":
100 codepage = Common.GetValidCodePage(attrib.Value, true, false, sourceLineNumbers);
101 break;
102 + case "SummaryInformationCodepage":
103 + summaryInformationCodepage = Common.GetValidCodePage(attrib.Value, true, false, sourceLineNumbers);
104 + break;
105 case "Culture":
106 culture = attrib.Value;
107 break;
@@ -143,7 +147,7 @@ namespace WixToolset.Core
147 }
148 }
149
146 - return messaging.EncounteredError ? null : new Localization(codepage, culture, variables, localizedControls);
150 + return messaging.EncounteredError ? null : new Localization(codepage, summaryInformationCodepage, culture, variables, localizedControls);
151 }
152
153 /// <summary>
@@ -254,24 +258,12 @@ namespace WixToolset.Core
258 break;
259 case "RightToLeft":
260 rightToLeft = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib);
257 - //if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib))
258 - //{
259 - // attribs |= MsiInterop.MsidbControlAttributesRTLRO;
260 - //}
261 break;
262 case "RightAligned":
263 rightAligned = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib);
264 - //if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib))
265 - //{
266 - // attribs |= MsiInterop.MsidbControlAttributesRightAligned;
267 - //}
264 break;
265 case "LeftScroll":
266 leftScroll = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib);
271 - //if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib))
272 - //{
273 - // attribs |= MsiInterop.MsidbControlAttributesLeftScroll;
274 - //}
267 break;
268 default:
269 Common.UnexpectedAttribute(messaging, sourceLineNumbers, attrib);
src/WixToolset.Core/ResolveResult.cs
+5 -1
@@ -8,7 +8,11 @@ namespace WixToolset.Core
8
9 internal class ResolveResult : IResolveResult
10 {
11 - public int Codepage { get; set; }
11 + public int? Codepage { get; set; }
12 +
13 + public int? SummaryInformationCodepage { get; set; }
14 +
15 + public int? PackageLcid { get; set; }
16
17 public IEnumerable<IDelayedField> DelayedFields { get; set; }
18
src/WixToolset.Core/Resolver.cs
+50 -31
@@ -4,6 +4,7 @@ namespace WixToolset.Core
4 {
5 using System;
6 using System.Collections.Generic;
7 + using System.Globalization;
8 using System.Linq;
9 using WixToolset.Core.Bind;
10 using WixToolset.Data;
@@ -22,26 +23,12 @@ namespace WixToolset.Core
23 this.ServiceProvider = serviceProvider;
24
25 this.Messaging = serviceProvider.GetService<IMessaging>();
25 -
26 - this.VariableResolver = serviceProvider.GetService<IVariableResolver>();
26 }
27
28 private IServiceProvider ServiceProvider { get; }
29
30 private IMessaging Messaging { get; }
31
33 - private IVariableResolver VariableResolver { get; set; }
34 -
35 - public IEnumerable<IBindPath> BindPaths { get; set; }
36 -
37 - public string IntermediateFolder { get; set; }
38 -
39 - public Intermediate IntermediateRepresentation { get; set; }
40 -
41 - public IEnumerable<Localization> Localizations { get; set; }
42 -
43 - public IEnumerable<string> FilterCultures { get; set; }
44 -
32 public IResolveResult Resolve(IResolveContext context)
33 {
34 foreach (var extension in context.Extensions)
@@ -52,11 +39,26 @@ namespace WixToolset.Core
39 ResolveResult resolveResult = null;
40 try
41 {
55 - var codepage = this.PopulateVariableResolver(context);
42 + var filteredLocalizations = FilterLocalizations(context);
43 +
44 + var variableResolver = this.CreateVariableResolver(context, filteredLocalizations);
45 +
46 + this.LocalizeUI(variableResolver, context.IntermediateRepresentation);
47 +
48 + resolveResult = this.DoResolve(context, variableResolver);
49 +
50 + var primaryLocalization = filteredLocalizations.FirstOrDefault();
51 +
52 + if (primaryLocalization != null)
53 + {
54 + this.TryGetCultureInfo(primaryLocalization.Culture, out var cultureInfo);
55
57 - this.LocalizeUI(context);
56 + resolveResult.Codepage = primaryLocalization.Codepage ?? cultureInfo?.TextInfo.ANSICodePage;
57
59 - resolveResult = this.DoResolve(context, codepage);
58 + resolveResult.SummaryInformationCodepage = primaryLocalization.SummaryInformationCodepage ?? primaryLocalization.Codepage ?? cultureInfo?.TextInfo.ANSICodePage;
59 +
60 + resolveResult.PackageLcid = cultureInfo?.LCID;
61 + }
62 }
63 finally
64 {
@@ -69,7 +71,7 @@ namespace WixToolset.Core
71 return resolveResult;
72 }
73
72 - private ResolveResult DoResolve(IResolveContext context, int? codepage)
74 + private ResolveResult DoResolve(IResolveContext context, IVariableResolver variableResolver)
75 {
76 var buildingPatch = context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch);
77
@@ -80,7 +82,7 @@ namespace WixToolset.Core
82 var command = new ResolveFieldsCommand();
83 command.Messaging = this.Messaging;
84 command.BuildingPatch = buildingPatch;
83 - command.VariableResolver = this.VariableResolver;
85 + command.VariableResolver = variableResolver;
86 command.BindPaths = context.BindPaths;
87 command.Extensions = context.Extensions;
88 command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles;
@@ -118,7 +120,6 @@ namespace WixToolset.Core
120
121 return new ResolveResult
122 {
121 - Codepage = codepage.HasValue ? codepage.Value : -1,
123 ExpectedEmbeddedFiles = expectedEmbeddedFiles,
124 DelayedFields = delayedFields,
125 IntermediateRepresentation = context.IntermediateRepresentation
@@ -128,13 +129,13 @@ namespace WixToolset.Core
129 /// <summary>
130 /// Localize dialogs and controls.
131 /// </summary>
131 - private void LocalizeUI(IResolveContext context)
132 + private void LocalizeUI(IVariableResolver variableResolver, Intermediate intermediate)
133 {
133 - foreach (var section in context.IntermediateRepresentation.Sections)
134 + foreach (var section in intermediate.Sections)
135 {
136 foreach (var symbol in section.Symbols.OfType<DialogSymbol>())
137 {
137 - if (this.VariableResolver.TryGetLocalizedControl(symbol.Id.Id, null, out var localizedControl))
138 + if (variableResolver.TryGetLocalizedControl(symbol.Id.Id, null, out var localizedControl))
139 {
140 if (CompilerConstants.IntegerNotSet != localizedControl.X)
141 {
@@ -169,7 +170,7 @@ namespace WixToolset.Core
170
171 foreach (var symbol in section.Symbols.OfType<ControlSymbol>())
172 {
172 - if (this.VariableResolver.TryGetLocalizedControl(symbol.DialogRef, symbol.Control, out var localizedControl))
173 + if (variableResolver.TryGetLocalizedControl(symbol.DialogRef, symbol.Control, out var localizedControl))
174 {
175 if (CompilerConstants.IntegerNotSet != localizedControl.X)
176 {
@@ -204,24 +205,42 @@ namespace WixToolset.Core
205 }
206 }
207
207 - private int? PopulateVariableResolver(IResolveContext context)
208 + private IVariableResolver CreateVariableResolver(IResolveContext context, IEnumerable<Localization> filteredLocalizations)
209 {
209 - var localizations = FilterLocalizations(context);
210 - var codepage = localizations.FirstOrDefault()?.Codepage;
210 + var variableResolver = this.ServiceProvider.GetService<IVariableResolver>();
211
212 - foreach (var localization in localizations)
212 + foreach (var localization in filteredLocalizations)
213 {
214 - this.VariableResolver.AddLocalization(localization);
214 + variableResolver.AddLocalization(localization);
215 }
216
217 // Gather all the wix variables.
218 var wixVariableSymbols = context.IntermediateRepresentation.Sections.SelectMany(s => s.Symbols).OfType<WixVariableSymbol>();
219 foreach (var symbol in wixVariableSymbols)
220 {
221 - this.VariableResolver.AddVariable(symbol.SourceLineNumbers, symbol.Id.Id, symbol.Value, symbol.Overridable);
221 + variableResolver.AddVariable(symbol.SourceLineNumbers, symbol.Id.Id, symbol.Value, symbol.Overridable);
222 + }
223 +
224 + return variableResolver;
225 + }
226 +
227 + private bool TryGetCultureInfo(string culture, out CultureInfo cultureInfo)
228 + {
229 + cultureInfo = null;
230 +
231 + if (!String.IsNullOrEmpty(culture))
232 + {
233 + try
234 + {
235 + cultureInfo = new CultureInfo(culture, useUserOverride: false);
236 + }
237 + catch
238 + {
239 + this.Messaging.Write("");
240 + }
241 }
242
224 - return codepage;
243 + return cultureInfo != null;
244 }
245
246 private static IEnumerable<Localization> FilterLocalizations(IResolveContext context)
src/test/WixToolsetTest.CoreIntegration/LanguageFixture.cs new
+155
@@ -0,0 +1,155 @@
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 +namespace WixToolsetTest.CoreIntegration
4 +{
5 + using System.IO;
6 + using System.Linq;
7 + using WixBuildTools.TestSupport;
8 + using WixToolset.Core.TestPackage;
9 + using WixToolset.Data;
10 + using WixToolset.Data.Symbols;
11 + using Xunit;
12 +
13 + public class LanguageFixture
14 + {
15 + [Fact]
16 + public void CanBuildWithDefaultProductLanguage()
17 + {
18 + var folder = TestData.Get(@"TestData", "Language");
19 +
20 + using (var fs = new DisposableFileSystem())
21 + {
22 + var baseFolder = fs.GetFolder();
23 +
24 + var result = WixRunner.Execute(new[]
25 + {
26 + "build",
27 + Path.Combine(folder, "Package.wxs"),
28 + "-loc", Path.Combine(folder, "Package.wxl"),
29 + "-bindpath", Path.Combine(folder, "data"),
30 + "-intermediateFolder", Path.Combine(baseFolder, "obj"),
31 + "-o", Path.Combine(baseFolder, @"bin\test.msi")
32 + });
33 +
34 + result.AssertSuccess();
35 +
36 + var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
37 + var section = intermediate.Sections.Single();
38 +
39 + var propertySymbol = section.Symbols.OfType<PropertySymbol>().Single(p => p.Id.Id == "ProductLanguage");
40 + Assert.Equal("0", propertySymbol.Value);
41 +
42 + var summaryPlatform = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.PlatformAndLanguage);
43 + Assert.Equal("Intel;0", summaryPlatform.Value);
44 +
45 + var summaryCodepage = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.Codepage);
46 + Assert.Equal("1252", summaryCodepage.Value);
47 + }
48 + }
49 +
50 + [Fact]
51 + public void CanBuildEnuWxl()
52 + {
53 + var folder = TestData.Get(@"TestData", "Language");
54 +
55 + using (var fs = new DisposableFileSystem())
56 + {
57 + var baseFolder = fs.GetFolder();
58 +
59 + var result = WixRunner.Execute(new[]
60 + {
61 + "build",
62 + Path.Combine(folder, "Package.wxs"),
63 + "-loc", Path.Combine(folder, "Package.en-us.wxl"),
64 + "-bindpath", Path.Combine(folder, "data"),
65 + "-intermediateFolder", Path.Combine(baseFolder, "obj"),
66 + "-o", Path.Combine(baseFolder, @"bin\test.msi")
67 + });
68 +
69 + result.AssertSuccess();
70 +
71 + var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
72 + var section = intermediate.Sections.Single();
73 +
74 + var propertySymbol = section.Symbols.OfType<PropertySymbol>().Single(p => p.Id.Id == "ProductLanguage");
75 + Assert.Equal("1033", propertySymbol.Value);
76 +
77 + var summaryPlatform = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.PlatformAndLanguage);
78 + Assert.Equal("Intel;1033", summaryPlatform.Value);
79 +
80 + var summaryCodepage = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.Codepage);
81 + Assert.Equal("1252", summaryCodepage.Value);
82 + }
83 + }
84 +
85 + [Fact]
86 + public void CanBuildJpnWxl()
87 + {
88 + var folder = TestData.Get(@"TestData", "Language");
89 +
90 + using (var fs = new DisposableFileSystem())
91 + {
92 + var baseFolder = fs.GetFolder();
93 +
94 + var result = WixRunner.Execute(new[]
95 + {
96 + "build",
97 + Path.Combine(folder, "Package.wxs"),
98 + "-loc", Path.Combine(folder, "Package.ja-jp.wxl"),
99 + "-bindpath", Path.Combine(folder, "data"),
100 + "-intermediateFolder", Path.Combine(baseFolder, "obj"),
101 + "-o", Path.Combine(baseFolder, @"bin\test.msi")
102 + });
103 +
104 + result.AssertSuccess();
105 +
106 + var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
107 + var section = intermediate.Sections.Single();
108 +
109 + var propertySymbol = section.Symbols.OfType<PropertySymbol>().Single(p => p.Id.Id == "ProductLanguage");
110 + Assert.Equal("1041", propertySymbol.Value);
111 +
112 + var summaryPlatform = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.PlatformAndLanguage);
113 + Assert.Equal("Intel;1041", summaryPlatform.Value);
114 +
115 + var summaryCodepage = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.Codepage);
116 + Assert.Equal("932", summaryCodepage.Value);
117 + }
118 + }
119 +
120 + [Fact]
121 + public void CanBuildJpnWxlWithEnuSummaryInfo()
122 + {
123 + var folder = TestData.Get(@"TestData", "Language");
124 +
125 + using (var fs = new DisposableFileSystem())
126 + {
127 + var baseFolder = fs.GetFolder();
128 +
129 + var result = WixRunner.Execute(new[]
130 + {
131 + "build",
132 + Path.Combine(folder, "Package.wxs"),
133 + "-loc", Path.Combine(folder, "PackageWithEnSummaryInfo.ja-jp.wxl"),
134 + "-bindpath", Path.Combine(folder, "data"),
135 + "-intermediateFolder", Path.Combine(baseFolder, "obj"),
136 + "-o", Path.Combine(baseFolder, @"bin\test.msi")
137 + });
138 +
139 + result.AssertSuccess();
140 +
141 + var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"));
142 + var section = intermediate.Sections.Single();
143 +
144 + var propertySymbol = section.Symbols.OfType<PropertySymbol>().Single(p => p.Id.Id == "ProductLanguage");
145 + Assert.Equal("1041", propertySymbol.Value);
146 +
147 + var summaryPlatform = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.PlatformAndLanguage);
148 + Assert.Equal("Intel;1041", summaryPlatform.Value);
149 +
150 + var summaryCodepage = section.Symbols.OfType<SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.Codepage);
151 + Assert.Equal("1252", summaryCodepage.Value);
152 + }
153 + }
154 + }
155 +}
src/test/WixToolsetTest.CoreIntegration/LinkerFixture.cs
+2 -2
@@ -19,8 +19,8 @@ namespace WixToolsetTest.CoreIntegration
19 [Fact]
20 public void MustCompileBeforeLinking()
21 {
22 - var intermediate1 = new Intermediate("TestIntermediate1", new[] { new IntermediateSection("test1", SectionType.Product, 65001) }, null);
23 - var intermediate2 = new Intermediate("TestIntermediate2", new[] { new IntermediateSection("test2", SectionType.Fragment, 65001) }, null);
22 + var intermediate1 = new Intermediate("TestIntermediate1", new[] { new IntermediateSection("test1", SectionType.Product) }, null);
23 + var intermediate2 = new Intermediate("TestIntermediate2", new[] { new IntermediateSection("test2", SectionType.Fragment) }, null);
24 var serviceProvider = WixToolsetServiceProviderFactory.CreateServiceProvider();
25
26 var listener = new TestMessageListener();
src/test/WixToolsetTest.CoreIntegration/ParseFixture.cs
+1 -1
@@ -16,7 +16,7 @@ namespace WixToolsetTest.CoreIntegration
16 public void GeneratesCorrectCustomActionIdentifiers()
17 {
18 var serviceProvider = WixToolsetServiceProviderFactory.CreateServiceProvider();
19 - var section = new IntermediateSection("section", SectionType.Fragment, 0);
19 + var section = new IntermediateSection("section", SectionType.Fragment);
20 var parseHelper = serviceProvider.GetService<IParseHelper>();
21
22 parseHelper.CreateCustomActionReference(null, section, "CustomAction32", Platform.X86, CustomActionPlatforms.X86);
src/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.en-us.wxl new
+7
@@ -0,0 +1,7 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
3 +
4 + <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
5 + <String Id="FeatureTitle">MsiPackage</String>
6 +
7 +</WixLocalization>
src/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.ja-jp.wxl new
+7
@@ -0,0 +1,7 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="ja-JP">
3 +
4 + <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
5 + <String Id="FeatureTitle">MsiPackage</String>
6 +
7 +</WixLocalization>
src/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.wxl new
+7
@@ -0,0 +1,7 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl">
3 +
4 + <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
5 + <String Id="FeatureTitle">MsiPackage</String>
6 +
7 +</WixLocalization>
src/test/WixToolsetTest.CoreIntegration/TestData/Language/Package.wxs new
+16
@@ -0,0 +1,16 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 + <Package Name="~DefaultLanguagePackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 +
4 + <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
5 +
6 + <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
7 + <Component Directory="INSTALLFOLDER">
8 + <File Source="test.txt" />
9 + </Component>
10 + </Feature>
11 + </Package>
12 +
13 + <Fragment>
14 + <Directory Id="INSTALLFOLDER" Name="ProgramFilesFolder:\MsiPackage" />
15 + </Fragment>
16 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/Language/PackageWithEnSummaryInfo.ja-jp.wxl new
+7
@@ -0,0 +1,7 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" SummaryInformationCodepage="1252" Culture="ja-JP">
3 +
4 + <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
5 + <String Id="FeatureTitle">MsiPackage</String>
6 +
7 +</WixLocalization>
src/test/WixToolsetTest.CoreIntegration/TestData/Language/data/test.txt new
+1
@@ -0,0 +1 @@
1 +This is test.txt.
\ No newline at end of file
src/test/WixToolsetTest.CoreIntegration/VariableResolverFixture.cs
+1 -1
@@ -25,7 +25,7 @@ namespace WixToolsetTest.CoreIntegration
25 { "ProductNameEditionVersion", new BindVariable() { Id = "ProductNameEditionVersion", Value = "!(loc.ProductNameEdition) v1.2.3" } },
26 };
27
28 - var localization = new Localization(0, "x-none", variables, new Dictionary<string,LocalizedControl>());
28 + var localization = new Localization(0, null, "x-none", variables, new Dictionary<string,LocalizedControl>());
29
30 variableResolver.AddLocalization(localization);
31