aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-02 14:41:49 -0700
committerRob Mensching <rob@firegiant.com>2021-04-02 14:58:00 -0700
commit4449fcc5b8d104817c67135229682c66c3d892ca (patch)
tree327f617de2e296ddb4e62c50bf07ec8b5dcf0a3e /src/WixToolset.Core
parent9cca339473d77c7036035f949239f5231c325968 (diff)
downloadwix-4449fcc5b8d104817c67135229682c66c3d892ca.tar.gz
wix-4449fcc5b8d104817c67135229682c66c3d892ca.tar.bz2
wix-4449fcc5b8d104817c67135229682c66c3d892ca.zip
Enable codepages and languages to be set via .wxl files
Fixes wixtoolset/issues#5801
Diffstat (limited to 'src/WixToolset.Core')
-rw-r--r--src/WixToolset.Core/BindContext.cs8
-rw-r--r--src/WixToolset.Core/CommandLine/BuildCommand.cs4
-rw-r--r--src/WixToolset.Core/Compiler.cs4
-rw-r--r--src/WixToolset.Core/CompilerCore.cs18
-rw-r--r--src/WixToolset.Core/Compiler_Bundle.cs2
-rw-r--r--src/WixToolset.Core/Compiler_Module.cs20
-rw-r--r--src/WixToolset.Core/Compiler_Package.cs46
-rw-r--r--src/WixToolset.Core/Compiler_Patch.cs9
-rw-r--r--src/WixToolset.Core/Compiler_PatchCreation.cs2
-rw-r--r--src/WixToolset.Core/IResolver.cs9
-rw-r--r--src/WixToolset.Core/Link/CollateLocalizationsCommand.cs4
-rw-r--r--src/WixToolset.Core/Linker.cs2
-rw-r--r--src/WixToolset.Core/LocalizationParser.cs20
-rw-r--r--src/WixToolset.Core/ResolveResult.cs6
-rw-r--r--src/WixToolset.Core/Resolver.cs81
15 files changed, 124 insertions, 111 deletions
diff --git a/src/WixToolset.Core/BindContext.cs b/src/WixToolset.Core/BindContext.cs
index 6b0a09a2..09454824 100644
--- a/src/WixToolset.Core/BindContext.cs
+++ b/src/WixToolset.Core/BindContext.cs
@@ -26,8 +26,6 @@ namespace WixToolset.Core
26 26
27 public string CabCachePath { get; set; } 27 public string CabCachePath { get; set; }
28 28
29 public int Codepage { get; set; }
30
31 public CompressionLevel? DefaultCompressionLevel { get; set; } 29 public CompressionLevel? DefaultCompressionLevel { get; set; }
32 30
33 public IEnumerable<IDelayedField> DelayedFields { get; set; } 31 public IEnumerable<IDelayedField> DelayedFields { get; set; }
@@ -50,6 +48,12 @@ namespace WixToolset.Core
50 48
51 public string PdbPath { get; set; } 49 public string PdbPath { get; set; }
52 50
51 public int? ResolvedCodepage { get; set; }
52
53 public int? ResolvedSummaryInformationCodepage { get; set; }
54
55 public int? ResolvedLcid { get; set; }
56
53 public IEnumerable<string> SuppressIces { get; set; } 57 public IEnumerable<string> SuppressIces { get; set; }
54 58
55 public bool SuppressValidation { get; set; } 59 public bool SuppressValidation { get; set; }
diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs
index 9efef830..59aa2f1f 100644
--- a/src/WixToolset.Core/CommandLine/BuildCommand.cs
+++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs
@@ -338,7 +338,9 @@ namespace WixToolset.Core.CommandLine
338 var context = this.ServiceProvider.GetService<IBindContext>(); 338 var context = this.ServiceProvider.GetService<IBindContext>();
339 //context.CabbingThreadCount = this.CabbingThreadCount; 339 //context.CabbingThreadCount = this.CabbingThreadCount;
340 context.CabCachePath = cabCachePath; 340 context.CabCachePath = cabCachePath;
341 context.Codepage = resolveResult.Codepage; 341 context.ResolvedCodepage = resolveResult.Codepage;
342 context.ResolvedSummaryInformationCodepage = resolveResult.SummaryInformationCodepage;
343 context.ResolvedLcid = resolveResult.PackageLcid;
342 context.DefaultCompressionLevel = this.DefaultCompressionLevel; 344 context.DefaultCompressionLevel = this.DefaultCompressionLevel;
343 context.DelayedFields = resolveResult.DelayedFields; 345 context.DelayedFields = resolveResult.DelayedFields;
344 context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; 346 context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles;
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs
index c2783481..926a46c5 100644
--- a/src/WixToolset.Core/Compiler.cs
+++ b/src/WixToolset.Core/Compiler.cs
@@ -384,7 +384,7 @@ namespace WixToolset.Core
384 { 384 {
385 var id = String.Concat(this.Core.ActiveSection.Id, ".", propertyId.Id); 385 var id = String.Concat(this.Core.ActiveSection.Id, ".", propertyId.Id);
386 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 388
389 // Reference the property in the active section. 389 // Reference the property in the active section.
390 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Property, propertyId.Id); 390 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Property, propertyId.Id);
@@ -6159,7 +6159,7 @@ namespace WixToolset.Core
6159 6159
6160 // NOTE: Id is not required for Fragments, this is a departure from the normal run of the mill processing. 6160 // NOTE: Id is not required for Fragments, this is a departure from the normal run of the mill processing.
6161 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 6163
6164 var featureDisplay = 0; 6164 var featureDisplay = 0;
6165 foreach (var child in node.Elements()) 6165 foreach (var child in node.Elements())
diff --git a/src/WixToolset.Core/CompilerCore.cs b/src/WixToolset.Core/CompilerCore.cs
index 0bc63d79..df532d74 100644
--- a/src/WixToolset.Core/CompilerCore.cs
+++ b/src/WixToolset.Core/CompilerCore.cs
@@ -680,7 +680,7 @@ namespace WixToolset.Core
680 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."); 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 682
683 string value = this.GetAttributeValue(sourceLineNumbers, attribute); 683 var value = this.GetAttributeValue(sourceLineNumbers, attribute);
684 684
685 if (0 < value.Length) 685 if (0 < value.Length)
686 { 686 {
@@ -692,7 +692,7 @@ namespace WixToolset.Core
692 { 692 {
693 try 693 try
694 { 694 {
695 int integer = Convert.ToInt32(value, CultureInfo.InvariantCulture.NumberFormat); 695 var integer = Convert.ToInt32(value, CultureInfo.InvariantCulture.NumberFormat);
696 696
697 if (CompilerConstants.IntegerNotSet == integer || CompilerConstants.IllegalInteger == integer) 697 if (CompilerConstants.IntegerNotSet == integer || CompilerConstants.IllegalInteger == integer)
698 { 698 {
@@ -1036,12 +1036,11 @@ namespace WixToolset.Core
1036 /// </summary> 1036 /// </summary>
1037 /// <param name="id">Unique identifier for the section.</param> 1037 /// <param name="id">Unique identifier for the section.</param>
1038 /// <param name="type">Type of section to create.</param> 1038 /// <param name="type">Type of section to create.</param>
1039 /// <param name="codepage">Codepage for the resulting database for this ection.</param> 1039 /// <param name="compilationId">Unique identifier for the compilation.</param>
1040 /// <param name="compilationId"></param>
1041 /// <returns>New section.</returns> 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)
1043 { 1042 {
1044 this.ActiveSection = this.CreateSection(id, type, codepage, compilationId); 1043 this.ActiveSection = this.CreateSection(id, type, compilationId);
1045 1044
1046 this.activeSectionCachedInlinedDirectoryIds = new Dictionary<string, string>(); 1045 this.activeSectionCachedInlinedDirectoryIds = new Dictionary<string, string>();
1047 this.activeSectionSimpleReferences = new HashSet<string>(); 1046 this.activeSectionSimpleReferences = new HashSet<string>();
@@ -1054,12 +1053,11 @@ namespace WixToolset.Core
1054 /// </summary> 1053 /// </summary>
1055 /// <param name="id">Unique identifier for the section.</param> 1054 /// <param name="id">Unique identifier for the section.</param>
1056 /// <param name="type">Type of section to create.</param> 1055 /// <param name="type">Type of section to create.</param>
1057 /// <param name="codepage">Codepage for the resulting database for this ection.</param> 1056 /// <param name="compilationId">Unique identifier for the compilation.</param>
1058 /// <param name="compilationId"></param>
1059 /// <returns>New section.</returns> 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)
1061 { 1059 {
1062 var section = new IntermediateSection(id, type, codepage, compilationId); 1060 var section = new IntermediateSection(id, type, compilationId);
1063 1061
1064 this.intermediate.Sections.Add(section); 1062 this.intermediate.Sections.Add(section);
1065 1063
diff --git a/src/WixToolset.Core/Compiler_Bundle.cs b/src/WixToolset.Core/Compiler_Bundle.cs
index 7e07532e..779ad376 100644
--- a/src/WixToolset.Core/Compiler_Bundle.cs
+++ b/src/WixToolset.Core/Compiler_Bundle.cs
@@ -259,7 +259,7 @@ namespace WixToolset.Core
259 } 259 }
260 260
261 this.activeName = String.IsNullOrEmpty(name) ? Common.GenerateGuid() : name; 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 263
264 // Now that the active section is initialized, process only extension attributes and the special ProviderKey attribute. 264 // Now that the active section is initialized, process only extension attributes and the special ProviderKey attribute.
265 foreach (var attrib in node.Attributes()) 265 foreach (var attrib in node.Attributes())
diff --git a/src/WixToolset.Core/Compiler_Module.cs b/src/WixToolset.Core/Compiler_Module.cs
index 597bc25c..59fe9164 100644
--- a/src/WixToolset.Core/Compiler_Module.cs
+++ b/src/WixToolset.Core/Compiler_Module.cs
@@ -104,7 +104,7 @@ namespace WixToolset.Core
104 try 104 try
105 { 105 {
106 this.compilingModule = true; // notice that we are actually building a Merge Module here 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 108
109 foreach (var child in node.Elements()) 109 foreach (var child in node.Elements())
110 { 110 {
@@ -232,15 +232,6 @@ namespace WixToolset.Core
232 232
233 if (!this.Core.EncounteredError) 233 if (!this.Core.EncounteredError)
234 { 234 {
235 if (!setCodepage)
236 {
237 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
238 {
239 PropertyId = SummaryInformationType.Codepage,
240 Value = "1252"
241 });
242 }
243
244 if (!setPackageName) 235 if (!setPackageName)
245 { 236 {
246 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers) 237 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
@@ -259,21 +250,20 @@ namespace WixToolset.Core
259 }); 250 });
260 } 251 }
261 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))
263 { 254 {
264 ModuleID = this.activeName, 255 ModuleId = this.activeName,
256 Language = this.activeLanguage,
265 Version = version 257 Version = version
266 }); 258 });
267 259
268 symbol.Set((int)ModuleSignatureSymbolFields.Language, this.activeLanguage);
269
270 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers) 260 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
271 { 261 {
272 PropertyId = SummaryInformationType.PackageCode, 262 PropertyId = SummaryInformationType.PackageCode,
273 Value = moduleId 263 Value = moduleId
274 }); 264 });
275 265
276 this.ValidateAndAddCommonSummaryInformationSymbols(sourceLineNumbers, msiVersion, platform); 266 this.ValidateAndAddCommonSummaryInformationSymbols(sourceLineNumbers, msiVersion, platform, this.activeLanguage);
277 } 267 }
278 } 268 }
279 finally 269 finally
diff --git a/src/WixToolset.Core/Compiler_Package.cs b/src/WixToolset.Core/Compiler_Package.cs
index fed08001..afe02f08 100644
--- a/src/WixToolset.Core/Compiler_Package.cs
+++ b/src/WixToolset.Core/Compiler_Package.cs
@@ -5,7 +5,6 @@ namespace WixToolset.Core
5 using System; 5 using System;
6 using System.Collections; 6 using System.Collections;
7 using System.Collections.Generic; 7 using System.Collections.Generic;
8 using System.Diagnostics.CodeAnalysis;
9 using System.Globalization; 8 using System.Globalization;
10 using System.IO; 9 using System.IO;
11 using System.Xml.Linq; 10 using System.Xml.Linq;
@@ -28,10 +27,10 @@ namespace WixToolset.Core
28 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 27 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
29 var compressed = YesNoDefaultType.Default; 28 var compressed = YesNoDefaultType.Default;
30 var sourceBits = 0; 29 var sourceBits = 0;
31 var codepage = 65001; 30 string codepage = null;
32 var productCode = "*"; 31 var productCode = "*";
32 string productLanguage = null;
33 var isPerMachine = true; 33 var isPerMachine = true;
34 string installScope = null;
35 string upgradeCode = null; 34 string upgradeCode = null;
36 string manufacturer = null; 35 string manufacturer = null;
37 string version = null; 36 string version = null;
@@ -53,7 +52,7 @@ namespace WixToolset.Core
53 switch (attrib.Name.LocalName) 52 switch (attrib.Name.LocalName)
54 { 53 {
55 case "Codepage": 54 case "Codepage":
56 codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib); 55 codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib);
57 break; 56 break;
58 case "Compressed": 57 case "Compressed":
59 compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); 58 compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
@@ -62,7 +61,7 @@ namespace WixToolset.Core
62 msiVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); 61 msiVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
63 break; 62 break;
64 case "Language": 63 case "Language":
65 this.activeLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); 64 productLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
66 break; 65 break;
67 case "Manufacturer": 66 case "Manufacturer":
68 manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters); 67 manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters);
@@ -82,7 +81,7 @@ namespace WixToolset.Core
82 productCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true); 81 productCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true);
83 break; 82 break;
84 case "Scope": 83 case "Scope":
85 installScope = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 84 var installScope = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
86 switch (installScope) 85 switch (installScope)
87 { 86 {
88 case "perMachine": 87 case "perMachine":
@@ -129,11 +128,6 @@ namespace WixToolset.Core
129 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); 128 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
130 } 129 }
131 130
132 if (null == this.activeLanguage)
133 {
134 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language"));
135 }
136
137 if (null == manufacturer) 131 if (null == manufacturer)
138 { 132 {
139 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); 133 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer"));
@@ -171,11 +165,11 @@ namespace WixToolset.Core
171 try 165 try
172 { 166 {
173 this.compilingProduct = true; 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);
175 169
176 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "Manufacturer"), manufacturer, false, false, false, true); 170 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "Manufacturer"), manufacturer, false, false, false, true);
177 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductCode"), productCode, 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);
179 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductName"), this.activeName, false, false, false, true); 173 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductName"), this.activeName, false, false, false, true);
180 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductVersion"), version, false, false, false, true); 174 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ProductVersion"), version, false, false, false, true);
181 if (null != upgradeCode) 175 if (null != upgradeCode)
@@ -188,7 +182,7 @@ namespace WixToolset.Core
188 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ALLUSERS"), "1", false, false, false, false); 182 this.AddProperty(sourceLineNumbers, new Identifier(AccessModifier.Global, "ALLUSERS"), "1", false, false, false, false);
189 } 183 }
190 184
191 this.ValidateAndAddCommonSummaryInformationSymbols(sourceLineNumbers, msiVersion, platform); 185 this.ValidateAndAddCommonSummaryInformationSymbols(sourceLineNumbers, msiVersion, platform, productLanguage);
192 186
193 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers) 187 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
194 { 188 {
@@ -198,7 +192,7 @@ namespace WixToolset.Core
198 192
199 var contextValues = new Dictionary<string, string> 193 var contextValues = new Dictionary<string, string>
200 { 194 {
201 ["ProductLanguage"] = this.activeLanguage, 195 ["ProductLanguage"] = productLanguage,
202 ["ProductVersion"] = version, 196 ["ProductVersion"] = version,
203 ["UpgradeCode"] = upgradeCode 197 ["UpgradeCode"] = upgradeCode
204 }; 198 };
@@ -360,14 +354,17 @@ namespace WixToolset.Core
360 354
361 if (!this.Core.EncounteredError) 355 if (!this.Core.EncounteredError)
362 { 356 {
363 if (!isCodepageSet) 357 this.Core.AddSymbol(new WixPackageSymbol(sourceLineNumbers)
364 { 358 {
365 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers) 359 PackageId = productCode,
366 { 360 UpgradeCode = upgradeCode,
367 PropertyId = SummaryInformationType.Codepage, 361 Name = this.activeName,
368 Value = "1252" 362 Language = productLanguage,
369 }); 363 Version = version,
370 } 364 Manufacturer = manufacturer,
365 Attributes = isPerMachine ? WixPackageAttributes.PerMachine : WixPackageAttributes.None,
366 Codepage = codepage,
367 });
371 368
372 if (!isPackageNameSet) 369 if (!isPackageNameSet)
373 { 370 {
@@ -435,7 +432,7 @@ namespace WixToolset.Core
435 } 432 }
436 } 433 }
437 434
438 private void ValidateAndAddCommonSummaryInformationSymbols(SourceLineNumber sourceLineNumbers, int msiVersion, string platform) 435 private void ValidateAndAddCommonSummaryInformationSymbols(SourceLineNumber sourceLineNumbers, int msiVersion, string platform, string language)
439 { 436 {
440 if (String.Equals(platform, "X64", StringComparison.OrdinalIgnoreCase) && 200 > msiVersion) 437 if (String.Equals(platform, "X64", StringComparison.OrdinalIgnoreCase) && 200 > msiVersion)
441 { 438 {
@@ -464,7 +461,7 @@ namespace WixToolset.Core
464 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers) 461 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
465 { 462 {
466 PropertyId = SummaryInformationType.PlatformAndLanguage, 463 PropertyId = SummaryInformationType.PlatformAndLanguage,
467 Value = String.Format(CultureInfo.InvariantCulture, "{0};{1}", platform, this.activeLanguage) 464 Value = $"{platform};{language}"
468 }); 465 });
469 466
470 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers) 467 this.Core.AddSymbol(new SummaryInformationSymbol(sourceLineNumbers)
@@ -478,7 +475,6 @@ namespace WixToolset.Core
478 PropertyId = SummaryInformationType.Security, 475 PropertyId = SummaryInformationType.Security,
479 Value = "2" 476 Value = "2"
480 }); 477 });
481
482 } 478 }
483 479
484 /// <summary> 480 /// <summary>
diff --git a/src/WixToolset.Core/Compiler_Patch.cs b/src/WixToolset.Core/Compiler_Patch.cs
index a2cadd67..c9cae183 100644
--- a/src/WixToolset.Core/Compiler_Patch.cs
+++ b/src/WixToolset.Core/Compiler_Patch.cs
@@ -24,7 +24,7 @@ namespace WixToolset.Core
24 { 24 {
25 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 25 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
26 string patchId = null; 26 string patchId = null;
27 var codepage = 0; 27 string codepage = null;
28 ////bool versionMismatches = false; 28 ////bool versionMismatches = false;
29 ////bool productMismatches = false; 29 ////bool productMismatches = false;
30 var allowRemoval = false; 30 var allowRemoval = false;
@@ -53,7 +53,7 @@ namespace WixToolset.Core
53 patchId = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true); 53 patchId = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true);
54 break; 54 break;
55 case "Codepage": 55 case "Codepage":
56 codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib); 56 codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib);
57 break; 57 break;
58 case "AllowMajorVersionMismatches": 58 case "AllowMajorVersionMismatches":
59 ////versionMismatches = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); 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")); 149 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer"));
150 } 150 }
151 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 153
154 foreach (var child in node.Elements()) 154 foreach (var child in node.Elements())
155 { 155 {
@@ -197,8 +197,9 @@ namespace WixToolset.Core
197 197
198 if (!this.Core.EncounteredError) 198 if (!this.Core.EncounteredError)
199 { 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 { 201 {
202 Codepage = codepage,
202 ClientPatchId = clientPatchId, 203 ClientPatchId = clientPatchId,
203 OptimizePatchSizeForLargeFiles = optimizePatchSizeForLargeFiles, 204 OptimizePatchSizeForLargeFiles = optimizePatchSizeForLargeFiles,
204 ApiPatchingSymbolFlags = apiPatchingSymbolFlags, 205 ApiPatchingSymbolFlags = apiPatchingSymbolFlags,
diff --git a/src/WixToolset.Core/Compiler_PatchCreation.cs b/src/WixToolset.Core/Compiler_PatchCreation.cs
index 7675a5c0..81ae4121 100644
--- a/src/WixToolset.Core/Compiler_PatchCreation.cs
+++ b/src/WixToolset.Core/Compiler_PatchCreation.cs
@@ -82,7 +82,7 @@ namespace WixToolset.Core
82 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); 82 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
83 } 83 }
84 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 86
87 foreach (var child in node.Elements()) 87 foreach (var child in node.Elements())
88 { 88 {
diff --git a/src/WixToolset.Core/IResolver.cs b/src/WixToolset.Core/IResolver.cs
index 3004ad2c..db25edbe 100644
--- a/src/WixToolset.Core/IResolver.cs
+++ b/src/WixToolset.Core/IResolver.cs
@@ -4,9 +4,16 @@ namespace WixToolset.Core
4{ 4{
5 using WixToolset.Extensibility.Data; 5 using WixToolset.Extensibility.Data;
6 6
7#pragma warning disable 1591 // TODO: add documentation 7 /// <summary>
8 /// Resolves localization and bind variables.
9 /// </summary>
8 public interface IResolver 10 public interface IResolver
9 { 11 {
12 /// <summary>
13 /// Resolve localization and bind variables.
14 /// </summary>
15 /// <param name="context">Resolve context.</param>
16 /// <returns>Resolve result.</returns>
10 IResolveResult Resolve(IResolveContext context); 17 IResolveResult Resolve(IResolveContext context);
11 } 18 }
12} 19}
diff --git a/src/WixToolset.Core/Link/CollateLocalizationsCommand.cs b/src/WixToolset.Core/Link/CollateLocalizationsCommand.cs
index ffa66210..d5c69838 100644
--- a/src/WixToolset.Core/Link/CollateLocalizationsCommand.cs
+++ b/src/WixToolset.Core/Link/CollateLocalizationsCommand.cs
@@ -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 2
3namespace WixToolset.Core.Link 3namespace WixToolset.Core.Link
4{ 4{
@@ -65,7 +65,7 @@ namespace WixToolset.Core.Link
65 } 65 }
66 } 66 }
67 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 } 69 }
70 } 70 }
71} 71}
diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs
index 320f7d1f..2c8508a8 100644
--- a/src/WixToolset.Core/Linker.cs
+++ b/src/WixToolset.Core/Linker.cs
@@ -180,7 +180,7 @@ namespace WixToolset.Core
180 180
181 // Create a new section to hold the linked content. Start with the entry section's 181 // Create a new section to hold the linked content. Start with the entry section's
182 // metadata. 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 184
185 var sectionCount = 0; 185 var sectionCount = 0;
186 186
diff --git a/src/WixToolset.Core/LocalizationParser.cs b/src/WixToolset.Core/LocalizationParser.cs
index dd5144ca..d6113fc6 100644
--- a/src/WixToolset.Core/LocalizationParser.cs
+++ b/src/WixToolset.Core/LocalizationParser.cs
@@ -86,7 +86,8 @@ namespace WixToolset.Core
86 private static Localization ParseWixLocalizationElement(IMessaging messaging, XElement node) 86 private static Localization ParseWixLocalizationElement(IMessaging messaging, XElement node)
87 { 87 {
88 var sourceLineNumbers = SourceLineNumber.CreateFromXObject(node); 88 var sourceLineNumbers = SourceLineNumber.CreateFromXObject(node);
89 var codepage = -1; 89 int? codepage = null;
90 int? summaryInformationCodepage = null;
90 string culture = null; 91 string culture = null;
91 92
92 foreach (var attrib in node.Attributes()) 93 foreach (var attrib in node.Attributes())
@@ -98,6 +99,9 @@ namespace WixToolset.Core
98 case "Codepage": 99 case "Codepage":
99 codepage = Common.GetValidCodePage(attrib.Value, true, false, sourceLineNumbers); 100 codepage = Common.GetValidCodePage(attrib.Value, true, false, sourceLineNumbers);
100 break; 101 break;
102 case "SummaryInformationCodepage":
103 summaryInformationCodepage = Common.GetValidCodePage(attrib.Value, true, false, sourceLineNumbers);
104 break;
101 case "Culture": 105 case "Culture":
102 culture = attrib.Value; 106 culture = attrib.Value;
103 break; 107 break;
@@ -143,7 +147,7 @@ namespace WixToolset.Core
143 } 147 }
144 } 148 }
145 149
146 return messaging.EncounteredError ? null : new Localization(codepage, culture, variables, localizedControls); 150 return messaging.EncounteredError ? null : new Localization(codepage, summaryInformationCodepage, culture, variables, localizedControls);
147 } 151 }
148 152
149 /// <summary> 153 /// <summary>
@@ -254,24 +258,12 @@ namespace WixToolset.Core
254 break; 258 break;
255 case "RightToLeft": 259 case "RightToLeft":
256 rightToLeft = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib); 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; 261 break;
262 case "RightAligned": 262 case "RightAligned":
263 rightAligned = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib); 263 rightAligned = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib);
264 //if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib))
265 //{
266 // attribs |= MsiInterop.MsidbControlAttributesRightAligned;
267 //}
268 break; 264 break;
269 case "LeftScroll": 265 case "LeftScroll":
270 leftScroll = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib); 266 leftScroll = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib);
271 //if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib))
272 //{
273 // attribs |= MsiInterop.MsidbControlAttributesLeftScroll;
274 //}
275 break; 267 break;
276 default: 268 default:
277 Common.UnexpectedAttribute(messaging, sourceLineNumbers, attrib); 269 Common.UnexpectedAttribute(messaging, sourceLineNumbers, attrib);
diff --git a/src/WixToolset.Core/ResolveResult.cs b/src/WixToolset.Core/ResolveResult.cs
index 6b6bc7c4..38b432b0 100644
--- a/src/WixToolset.Core/ResolveResult.cs
+++ b/src/WixToolset.Core/ResolveResult.cs
@@ -8,7 +8,11 @@ namespace WixToolset.Core
8 8
9 internal class ResolveResult : IResolveResult 9 internal class ResolveResult : IResolveResult
10 { 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; }
12 16
13 public IEnumerable<IDelayedField> DelayedFields { get; set; } 17 public IEnumerable<IDelayedField> DelayedFields { get; set; }
14 18
diff --git a/src/WixToolset.Core/Resolver.cs b/src/WixToolset.Core/Resolver.cs
index 92c2a9c9..f4cb2fd6 100644
--- a/src/WixToolset.Core/Resolver.cs
+++ b/src/WixToolset.Core/Resolver.cs
@@ -4,6 +4,7 @@ namespace WixToolset.Core
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Globalization;
7 using System.Linq; 8 using System.Linq;
8 using WixToolset.Core.Bind; 9 using WixToolset.Core.Bind;
9 using WixToolset.Data; 10 using WixToolset.Data;
@@ -22,26 +23,12 @@ namespace WixToolset.Core
22 this.ServiceProvider = serviceProvider; 23 this.ServiceProvider = serviceProvider;
23 24
24 this.Messaging = serviceProvider.GetService<IMessaging>(); 25 this.Messaging = serviceProvider.GetService<IMessaging>();
25
26 this.VariableResolver = serviceProvider.GetService<IVariableResolver>();
27 } 26 }
28 27
29 private IServiceProvider ServiceProvider { get; } 28 private IServiceProvider ServiceProvider { get; }
30 29
31 private IMessaging Messaging { get; } 30 private IMessaging Messaging { get; }
32 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
45 public IResolveResult Resolve(IResolveContext context) 32 public IResolveResult Resolve(IResolveContext context)
46 { 33 {
47 foreach (var extension in context.Extensions) 34 foreach (var extension in context.Extensions)
@@ -52,11 +39,26 @@ namespace WixToolset.Core
52 ResolveResult resolveResult = null; 39 ResolveResult resolveResult = null;
53 try 40 try
54 { 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);
56 55
57 this.LocalizeUI(context); 56 resolveResult.Codepage = primaryLocalization.Codepage ?? cultureInfo?.TextInfo.ANSICodePage;
58 57
59 resolveResult = this.DoResolve(context, codepage); 58 resolveResult.SummaryInformationCodepage = primaryLocalization.SummaryInformationCodepage ?? primaryLocalization.Codepage ?? cultureInfo?.TextInfo.ANSICodePage;
59
60 resolveResult.PackageLcid = cultureInfo?.LCID;
61 }
60 } 62 }
61 finally 63 finally
62 { 64 {
@@ -69,7 +71,7 @@ namespace WixToolset.Core
69 return resolveResult; 71 return resolveResult;
70 } 72 }
71 73
72 private ResolveResult DoResolve(IResolveContext context, int? codepage) 74 private ResolveResult DoResolve(IResolveContext context, IVariableResolver variableResolver)
73 { 75 {
74 var buildingPatch = context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch); 76 var buildingPatch = context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch);
75 77
@@ -80,7 +82,7 @@ namespace WixToolset.Core
80 var command = new ResolveFieldsCommand(); 82 var command = new ResolveFieldsCommand();
81 command.Messaging = this.Messaging; 83 command.Messaging = this.Messaging;
82 command.BuildingPatch = buildingPatch; 84 command.BuildingPatch = buildingPatch;
83 command.VariableResolver = this.VariableResolver; 85 command.VariableResolver = variableResolver;
84 command.BindPaths = context.BindPaths; 86 command.BindPaths = context.BindPaths;
85 command.Extensions = context.Extensions; 87 command.Extensions = context.Extensions;
86 command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; 88 command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles;
@@ -118,7 +120,6 @@ namespace WixToolset.Core
118 120
119 return new ResolveResult 121 return new ResolveResult
120 { 122 {
121 Codepage = codepage.HasValue ? codepage.Value : -1,
122 ExpectedEmbeddedFiles = expectedEmbeddedFiles, 123 ExpectedEmbeddedFiles = expectedEmbeddedFiles,
123 DelayedFields = delayedFields, 124 DelayedFields = delayedFields,
124 IntermediateRepresentation = context.IntermediateRepresentation 125 IntermediateRepresentation = context.IntermediateRepresentation
@@ -128,13 +129,13 @@ namespace WixToolset.Core
128 /// <summary> 129 /// <summary>
129 /// Localize dialogs and controls. 130 /// Localize dialogs and controls.
130 /// </summary> 131 /// </summary>
131 private void LocalizeUI(IResolveContext context) 132 private void LocalizeUI(IVariableResolver variableResolver, Intermediate intermediate)
132 { 133 {
133 foreach (var section in context.IntermediateRepresentation.Sections) 134 foreach (var section in intermediate.Sections)
134 { 135 {
135 foreach (var symbol in section.Symbols.OfType<DialogSymbol>()) 136 foreach (var symbol in section.Symbols.OfType<DialogSymbol>())
136 { 137 {
137 if (this.VariableResolver.TryGetLocalizedControl(symbol.Id.Id, null, out var localizedControl)) 138 if (variableResolver.TryGetLocalizedControl(symbol.Id.Id, null, out var localizedControl))
138 { 139 {
139 if (CompilerConstants.IntegerNotSet != localizedControl.X) 140 if (CompilerConstants.IntegerNotSet != localizedControl.X)
140 { 141 {
@@ -169,7 +170,7 @@ namespace WixToolset.Core
169 170
170 foreach (var symbol in section.Symbols.OfType<ControlSymbol>()) 171 foreach (var symbol in section.Symbols.OfType<ControlSymbol>())
171 { 172 {
172 if (this.VariableResolver.TryGetLocalizedControl(symbol.DialogRef, symbol.Control, out var localizedControl)) 173 if (variableResolver.TryGetLocalizedControl(symbol.DialogRef, symbol.Control, out var localizedControl))
173 { 174 {
174 if (CompilerConstants.IntegerNotSet != localizedControl.X) 175 if (CompilerConstants.IntegerNotSet != localizedControl.X)
175 { 176 {
@@ -204,24 +205,42 @@ namespace WixToolset.Core
204 } 205 }
205 } 206 }
206 207
207 private int? PopulateVariableResolver(IResolveContext context) 208 private IVariableResolver CreateVariableResolver(IResolveContext context, IEnumerable<Localization> filteredLocalizations)
208 { 209 {
209 var localizations = FilterLocalizations(context); 210 var variableResolver = this.ServiceProvider.GetService<IVariableResolver>();
210 var codepage = localizations.FirstOrDefault()?.Codepage;
211 211
212 foreach (var localization in localizations) 212 foreach (var localization in filteredLocalizations)
213 { 213 {
214 this.VariableResolver.AddLocalization(localization); 214 variableResolver.AddLocalization(localization);
215 } 215 }
216 216
217 // Gather all the wix variables. 217 // Gather all the wix variables.
218 var wixVariableSymbols = context.IntermediateRepresentation.Sections.SelectMany(s => s.Symbols).OfType<WixVariableSymbol>(); 218 var wixVariableSymbols = context.IntermediateRepresentation.Sections.SelectMany(s => s.Symbols).OfType<WixVariableSymbol>();
219 foreach (var symbol in wixVariableSymbols) 219 foreach (var symbol in wixVariableSymbols)
220 { 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 }
222 } 241 }
223 242
224 return codepage; 243 return cultureInfo != null;
225 } 244 }
226 245
227 private static IEnumerable<Localization> FilterLocalizations(IResolveContext context) 246 private static IEnumerable<Localization> FilterLocalizations(IResolveContext context)