@joebigelow / wix / commits / 4418bd52

Migrate MsgGen

Rob Mensching committed Aug 15, 2017 at 01:31 UTC 4418bd52f1fca52a0d8d5f5b60abd2fdfc7146bd
8 files changed +765
WixBuildTools.sln
+15
@@ -6,6 +6,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{00E50075-E89
6 EndProject
7 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixBuildTools.XsdGen", "src\WixBuildTools.XsdGen\WixBuildTools.XsdGen.csproj", "{E89E52C9-A4A1-4174-A1B1-3B72975E6ED6}"
8 EndProject
9 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixBuildTools.MsgGen", "src\WixBuildTools.MsgGen\WixBuildTools.MsgGen.csproj", "{DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}"
10 +EndProject
11 Global
12 GlobalSection(SolutionConfigurationPlatforms) = preSolution
13 Debug|Any CPU = Debug|Any CPU
@@ -28,12 +30,25 @@ Global
30 {E89E52C9-A4A1-4174-A1B1-3B72975E6ED6}.Release|x64.Build.0 = Release|Any CPU
31 {E89E52C9-A4A1-4174-A1B1-3B72975E6ED6}.Release|x86.ActiveCfg = Release|Any CPU
32 {E89E52C9-A4A1-4174-A1B1-3B72975E6ED6}.Release|x86.Build.0 = Release|Any CPU
33 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Debug|x64.ActiveCfg = Debug|Any CPU
36 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Debug|x64.Build.0 = Debug|Any CPU
37 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Debug|x86.ActiveCfg = Debug|Any CPU
38 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Debug|x86.Build.0 = Debug|Any CPU
39 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Release|Any CPU.Build.0 = Release|Any CPU
41 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Release|x64.ActiveCfg = Release|Any CPU
42 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Release|x64.Build.0 = Release|Any CPU
43 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Release|x86.ActiveCfg = Release|Any CPU
44 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4}.Release|x86.Build.0 = Release|Any CPU
45 EndGlobalSection
46 GlobalSection(SolutionProperties) = preSolution
47 HideSolutionNode = FALSE
48 EndGlobalSection
49 GlobalSection(NestedProjects) = preSolution
50 {E89E52C9-A4A1-4174-A1B1-3B72975E6ED6} = {00E50075-E896-42D1-AC30-2D2E7D129FB9}
51 + {DB6EF6F3-51B1-4214-9A14-D501C23F6FA4} = {00E50075-E896-42D1-AC30-2D2E7D129FB9}
52 EndGlobalSection
53 GlobalSection(ExtensibilityGlobals) = postSolution
54 SolutionGuid = {83E9E075-B440-471A-9C37-9D84BA0AE3E0}
src/WixBuildTools.MsgGen/AssemblyInfo.cs new
+8
@@ -0,0 +1,8 @@
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 +using System.Reflection;
4 +
5 +// General Information about an assembly is controlled through the following
6 +// set of attributes. Change these attribute values to modify the information
7 +// associated with an assembly.
8 +[assembly: AssemblyCulture("")]
src/WixBuildTools.MsgGen/GenerateMessageFiles.cs new
+250
@@ -0,0 +1,250 @@
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 WixBuildTools.MsgGen
4 +{
5 + using System;
6 + using System.CodeDom;
7 + using System.Collections;
8 + using System.Globalization;
9 + using System.Reflection;
10 + using System.Resources;
11 + using System.Xml;
12 +
13 + /// <summary>
14 + /// Message files generation class.
15 + /// </summary>
16 + public class GenerateMessageFiles
17 + {
18 + /// <summary>
19 + /// Generate the message files.
20 + /// </summary>
21 + /// <param name="messagesDoc">Input Xml document containing message definitions.</param>
22 + /// <param name="codeCompileUnit">CodeDom container.</param>
23 + /// <param name="resourceWriter">Writer for default resource file.</param>
24 + public static void Generate(XmlDocument messagesDoc, CodeCompileUnit codeCompileUnit, ResourceWriter resourceWriter)
25 + {
26 + Hashtable usedNumbers = new Hashtable();
27 +
28 + if (null == messagesDoc)
29 + {
30 + throw new ArgumentNullException("messagesDoc");
31 + }
32 +
33 + if (null == codeCompileUnit)
34 + {
35 + throw new ArgumentNullException("codeCompileUnit");
36 + }
37 +
38 + if (null == resourceWriter)
39 + {
40 + throw new ArgumentNullException("resourceWriter");
41 + }
42 +
43 + string namespaceAttr = messagesDoc.DocumentElement.GetAttribute("Namespace");
44 + string resourcesAttr = messagesDoc.DocumentElement.GetAttribute("Resources");
45 +
46 + // namespace
47 + CodeNamespace messagesNamespace = new CodeNamespace(namespaceAttr);
48 + codeCompileUnit.Namespaces.Add(messagesNamespace);
49 +
50 + // imports
51 + messagesNamespace.Imports.Add(new CodeNamespaceImport("System"));
52 + messagesNamespace.Imports.Add(new CodeNamespaceImport("System.Reflection"));
53 + messagesNamespace.Imports.Add(new CodeNamespaceImport("System.Resources"));
54 + if (namespaceAttr != "WixToolset.Data")
55 + {
56 + messagesNamespace.Imports.Add(new CodeNamespaceImport("WixToolset.Data"));
57 + }
58 +
59 + foreach (XmlElement classElement in messagesDoc.DocumentElement.ChildNodes)
60 + {
61 + string className = classElement.GetAttribute("Name");
62 + string baseContainerName = classElement.GetAttribute("BaseContainerName");
63 + string containerName = classElement.GetAttribute("ContainerName");
64 + string messageLevel = classElement.GetAttribute("Level");
65 +
66 + // message container class
67 + messagesNamespace.Types.Add(CreateContainer(namespaceAttr, baseContainerName, containerName, messageLevel, resourcesAttr));
68 +
69 + // class
70 + CodeTypeDeclaration messagesClass = new CodeTypeDeclaration(className);
71 + messagesClass.TypeAttributes = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;
72 + messagesNamespace.Types.Add(messagesClass);
73 +
74 + // private constructor (needed since all methods in this class are static)
75 + CodeConstructor constructor = new CodeConstructor();
76 + constructor.Attributes = MemberAttributes.Private;
77 + constructor.ReturnType = null;
78 + messagesClass.Members.Add(constructor);
79 +
80 + // messages
81 + foreach (XmlElement messageElement in classElement.ChildNodes)
82 + {
83 + int number;
84 + string id = messageElement.GetAttribute("Id");
85 + string numberString = messageElement.GetAttribute("Number");
86 + bool sourceLineNumbers = true;
87 +
88 + // determine the message number (and ensure it was set properly)
89 + if (0 < numberString.Length)
90 + {
91 + number = Convert.ToInt32(numberString, CultureInfo.InvariantCulture);
92 + }
93 + else
94 + {
95 + throw new ApplicationException(String.Format("Message number must be assigned for {0} '{1}'.", containerName, id));
96 + }
97 +
98 + // check for message number collisions
99 + if (usedNumbers.Contains(number))
100 + {
101 + throw new ApplicationException(String.Format("Collision detected between two or more messages with number '{0}'.", number));
102 + }
103 +
104 + usedNumbers.Add(number, null);
105 +
106 + if ("no" == messageElement.GetAttribute("SourceLineNumbers"))
107 + {
108 + sourceLineNumbers = false;
109 + }
110 +
111 + int instanceCount = 0;
112 + foreach (XmlElement instanceElement in messageElement.ChildNodes)
113 + {
114 + string formatString = instanceElement.InnerText.Trim();
115 + string resourceName = String.Concat(className, "_", id, "_", (++instanceCount).ToString());
116 +
117 + // create a resource
118 + resourceWriter.AddResource(resourceName, formatString);
119 +
120 + // create method
121 + CodeMemberMethod method = new CodeMemberMethod();
122 + method.ReturnType = new CodeTypeReference(baseContainerName);
123 + method.Attributes = MemberAttributes.Public | MemberAttributes.Static;
124 + messagesClass.Members.Add(method);
125 +
126 + // method name
127 + method.Name = id;
128 +
129 + // return statement
130 + CodeMethodReturnStatement stmt = new CodeMethodReturnStatement();
131 + method.Statements.Add(stmt);
132 +
133 + // return statement expression
134 + CodeObjectCreateExpression expr = new CodeObjectCreateExpression();
135 + stmt.Expression = expr;
136 +
137 + // new struct
138 + expr.CreateType = new CodeTypeReference(containerName);
139 +
140 + // optionally have sourceLineNumbers as the first parameter
141 + if (sourceLineNumbers)
142 + {
143 + // sourceLineNumbers parameter
144 + expr.Parameters.Add(new CodeArgumentReferenceExpression("sourceLineNumbers"));
145 + }
146 + else
147 + {
148 + expr.Parameters.Add(new CodePrimitiveExpression(null));
149 + }
150 +
151 + // message number parameter
152 + expr.Parameters.Add(new CodePrimitiveExpression(number));
153 +
154 + // resource name parameter
155 + expr.Parameters.Add(new CodePrimitiveExpression(resourceName));
156 +
157 + // optionally have sourceLineNumbers as the first parameter
158 + if (sourceLineNumbers)
159 + {
160 + method.Parameters.Add(new CodeParameterDeclarationExpression("SourceLineNumber", "sourceLineNumbers"));
161 + }
162 +
163 + foreach (XmlNode parameterNode in instanceElement.ChildNodes)
164 + {
165 + XmlElement parameterElement;
166 +
167 + if (null != (parameterElement = parameterNode as XmlElement))
168 + {
169 + string type = parameterElement.GetAttribute("Type");
170 + string name = parameterElement.GetAttribute("Name");
171 +
172 + // method parameter
173 + method.Parameters.Add(new CodeParameterDeclarationExpression(type, name));
174 +
175 + // String.Format parameter
176 + expr.Parameters.Add(new CodeArgumentReferenceExpression(name));
177 + }
178 + }
179 + }
180 + }
181 + }
182 + }
183 +
184 + /// <summary>
185 + /// Create message container class.
186 + /// </summary>
187 + /// <param name="namespaceName">Namespace to use for resources stream.</param>
188 + /// <param name="baseContainerName">Name of the base message container class.</param>
189 + /// <param name="containerName">Name of the message container class.</param>
190 + /// <param name="messageLevel">Message level of for the message.</param>
191 + /// <param name="resourcesName">Name of the resources stream (will get namespace prepended).</param>
192 + /// <returns>Message container class CodeDom object.</returns>
193 + private static CodeTypeDeclaration CreateContainer(string namespaceName, string baseContainerName, string containerName, string messageLevel, string resourcesName)
194 + {
195 + CodeTypeDeclaration messageContainer = new CodeTypeDeclaration();
196 +
197 + messageContainer.Name = containerName;
198 + messageContainer.BaseTypes.Add(new CodeTypeReference(baseContainerName));
199 +
200 + // constructor
201 + CodeConstructor constructor = new CodeConstructor();
202 + constructor.Attributes = MemberAttributes.Public;
203 + constructor.ReturnType = null;
204 + messageContainer.Members.Add(constructor);
205 +
206 + CodeMemberField resourceManager = new CodeMemberField();
207 + resourceManager.Attributes = MemberAttributes.Private | MemberAttributes.Static;
208 + resourceManager.Name = "resourceManager";
209 + resourceManager.Type = new CodeTypeReference("ResourceManager");
210 + resourceManager.InitExpression = new CodeObjectCreateExpression("ResourceManager", new CodeSnippetExpression(String.Format("\"{0}.{1}\"", namespaceName, resourcesName)), new CodeSnippetExpression("Assembly.GetExecutingAssembly()"));
211 + messageContainer.Members.Add(resourceManager);
212 +
213 + // constructor parameters
214 + constructor.Parameters.Add(new CodeParameterDeclarationExpression("SourceLineNumber", "sourceLineNumbers"));
215 + constructor.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "id"));
216 + constructor.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "resourceName"));
217 + CodeParameterDeclarationExpression messageArgsParam = new CodeParameterDeclarationExpression("params object[]", "messageArgs");
218 + constructor.Parameters.Add(messageArgsParam);
219 +
220 + constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("sourceLineNumbers"));
221 + constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("id"));
222 + constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("resourceName"));
223 + constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("messageArgs"));
224 +
225 + // assign base.Level if messageLevel is specified
226 + if (!String.IsNullOrEmpty(messageLevel))
227 + {
228 + CodePropertyReferenceExpression levelReference = new CodePropertyReferenceExpression(new CodeBaseReferenceExpression(), "Level");
229 + CodeFieldReferenceExpression messageLevelField = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("MessageLevel"), messageLevel);
230 + constructor.Statements.Add(new CodeAssignStatement(levelReference, messageLevelField));
231 + }
232 +
233 + // Assign base.ResourceManager property
234 + CodePropertyReferenceExpression baseResourceManagerReference = new CodePropertyReferenceExpression(new CodeBaseReferenceExpression(), "ResourceManager");
235 + CodeFieldReferenceExpression resourceManagerField = new CodeFieldReferenceExpression(null, "resourceManager");
236 + constructor.Statements.Add(new CodeAssignStatement(baseResourceManagerReference, resourceManagerField));
237 +
238 + //CodeMemberProperty resourceManagerProperty = new CodeMemberProperty();
239 + //resourceManagerProperty.Attributes = MemberAttributes.Public | MemberAttributes.Override;
240 + //resourceManagerProperty.Name = "ResourceManager";
241 + //resourceManagerProperty.Type = new CodeTypeReference("ResourceManager");
242 + //CodeFieldReferenceExpression resourceManagerReference = new CodeFieldReferenceExpression();
243 + //resourceManagerReference.FieldName = "resourceManager";
244 + //resourceManagerProperty.GetStatements.Add(new CodeMethodReturnStatement(resourceManagerReference));
245 + //messageContainer.Members.Add(resourceManagerProperty);
246 +
247 + return messageContainer;
248 + }
249 + }
250 +}
src/WixBuildTools.MsgGen/MsgGen.cs new
+261
@@ -0,0 +1,261 @@
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 WixBuildTools.MsgGen
4 +{
5 + using Microsoft.CSharp;
6 + using System;
7 + using System.CodeDom;
8 + using System.CodeDom.Compiler;
9 + using System.Collections;
10 + using System.IO;
11 + using System.Reflection;
12 + using System.Resources;
13 + using System.Runtime.InteropServices;
14 + using System.Xml;
15 + using System.Xml.Schema;
16 +
17 + /// <summary>
18 + /// The main entry point for MsgGen.
19 + /// </summary>
20 + public class MsgGen
21 + {
22 + /// <summary>
23 + /// The main entry point for MsgGen.
24 + /// </summary>
25 + /// <param name="args">Commandline arguments for the application.</param>
26 + /// <returns>Returns the application error code.</returns>
27 + [STAThread]
28 + public static int Main(string[] args)
29 + {
30 + try
31 + {
32 + MsgGenMain msgGen = new MsgGenMain(args);
33 + }
34 + catch (Exception e)
35 + {
36 + Console.WriteLine("MsgGen.exe : fatal error MSGG0000: {0}\r\n\r\nStack Trace:\r\n{1}", e.Message, e.StackTrace);
37 + if (e is NullReferenceException || e is SEHException)
38 + {
39 + throw;
40 + }
41 + return 2;
42 + }
43 +
44 + return 0;
45 + }
46 +
47 + /// <summary>
48 + /// Main class for MsgGen.
49 + /// </summary>
50 + private class MsgGenMain
51 + {
52 + private bool showLogo;
53 + private bool showHelp;
54 +
55 + private string sourceFile;
56 + private string destClassFile;
57 + private string destResourcesFile;
58 +
59 + /// <summary>
60 + /// Main method for the MsgGen application within the MsgGenMain class.
61 + /// </summary>
62 + /// <param name="args">Commandline arguments to the application.</param>
63 + public MsgGenMain(string[] args)
64 + {
65 + this.showLogo = true;
66 + this.showHelp = false;
67 +
68 + this.sourceFile = null;
69 + this.destClassFile = null;
70 + this.destResourcesFile = null;
71 +
72 + // parse the command line
73 + this.ParseCommandLine(args);
74 +
75 + if (null == this.sourceFile || null == this.destClassFile)
76 + {
77 + this.showHelp = true;
78 + }
79 + if (null == this.destResourcesFile)
80 + {
81 + this.destResourcesFile = Path.ChangeExtension(this.destClassFile, ".resources");
82 + }
83 +
84 + // get the assemblies
85 + Assembly msgGenAssembly = Assembly.GetExecutingAssembly();
86 +
87 + if (this.showLogo)
88 + {
89 + Console.WriteLine("Microsoft (R) Message Generation Tool version {0}", msgGenAssembly.GetName().Version.ToString());
90 + Console.WriteLine("Copyright (C) Microsoft Corporation 2004. All rights reserved.");
91 + Console.WriteLine();
92 + }
93 + if (this.showHelp)
94 + {
95 + Console.WriteLine(" usage: MsgGen.exe [-?] [-nologo] sourceFile destClassFile [destResourcesFile]");
96 + Console.WriteLine();
97 + Console.WriteLine(" -? this help information");
98 + Console.WriteLine();
99 + Console.WriteLine("For more information see: http://wix.sourceforge.net");
100 + return; // exit
101 + }
102 +
103 + // load the schema
104 + XmlReader reader = null;
105 + XmlSchemaCollection schemaCollection = null;
106 + try
107 + {
108 + reader = new XmlTextReader(msgGenAssembly.GetManifestResourceStream("WixBuildTools.MsgGen.Xsd.messages.xsd"));
109 + schemaCollection = new XmlSchemaCollection();
110 + schemaCollection.Add("http://schemas.microsoft.com/genmsgs/2004/07/messages", reader);
111 + }
112 + finally
113 + {
114 + reader.Close();
115 + }
116 +
117 + // load the source file and process it
118 + using (StreamReader sr = new StreamReader(this.sourceFile))
119 + {
120 + XmlParserContext context = new XmlParserContext(null, null, null, XmlSpace.None);
121 + XmlValidatingReader validatingReader = new XmlValidatingReader(sr.BaseStream, XmlNodeType.Document, context);
122 + validatingReader.Schemas.Add(schemaCollection);
123 +
124 + XmlDocument errorsDoc = new XmlDocument();
125 + errorsDoc.Load(validatingReader);
126 +
127 + CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
128 +
129 + using (ResourceWriter resourceWriter = new ResourceWriter(this.destResourcesFile))
130 + {
131 + GenerateMessageFiles.Generate(errorsDoc, codeCompileUnit, resourceWriter);
132 +
133 + GenerateCSharpCode(codeCompileUnit, this.destClassFile);
134 + }
135 + }
136 + }
137 +
138 + /// <summary>
139 + /// Generate the actual C# code.
140 + /// </summary>
141 + /// <param name="codeCompileUnit">The code DOM.</param>
142 + /// <param name="destClassFile">Destination C# source file.</param>
143 + public static void GenerateCSharpCode(CodeCompileUnit codeCompileUnit, string destClassFile)
144 + {
145 + // generate the code with the C# code provider
146 + CSharpCodeProvider provider = new CSharpCodeProvider();
147 +
148 + // obtain an ICodeGenerator from the CodeDomProvider class
149 + ICodeGenerator gen = provider.CreateGenerator();
150 +
151 + // create a TextWriter to a StreamWriter to the output file
152 + using (StreamWriter sw = new StreamWriter(destClassFile))
153 + {
154 + using (IndentedTextWriter tw = new IndentedTextWriter(sw, " "))
155 + {
156 + CodeGeneratorOptions options = new CodeGeneratorOptions();
157 +
158 + // code generation options
159 + options.BlankLinesBetweenMembers = true;
160 + options.BracingStyle = "C";
161 +
162 + // generate source code using the code generator
163 + gen.GenerateCodeFromCompileUnit(codeCompileUnit, tw, options);
164 + }
165 + }
166 + }
167 +
168 + /// <summary>
169 + /// Parse the commandline arguments.
170 + /// </summary>
171 + /// <param name="args">Commandline arguments.</param>
172 + private void ParseCommandLine(string[] args)
173 + {
174 + for (int i = 0; i < args.Length; ++i)
175 + {
176 + string arg = args[i];
177 + if (null == arg || "" == arg) // skip blank arguments
178 + {
179 + continue;
180 + }
181 +
182 + if ('-' == arg[0] || '/' == arg[0])
183 + {
184 + string parameter = arg.Substring(1);
185 + if ("nologo" == parameter)
186 + {
187 + this.showLogo = false;
188 + }
189 + else if ("?" == parameter || "help" == parameter)
190 + {
191 + this.showHelp = true;
192 + }
193 + }
194 + else if ('@' == arg[0])
195 + {
196 + using (StreamReader reader = new StreamReader(arg.Substring(1)))
197 + {
198 + string line;
199 + ArrayList newArgs = new ArrayList();
200 +
201 + while (null != (line = reader.ReadLine()))
202 + {
203 + string newArg = "";
204 + bool betweenQuotes = false;
205 + for (int j = 0; j < line.Length; ++j)
206 + {
207 + // skip whitespace
208 + if (!betweenQuotes && (' ' == line[j] || '\t' == line[j]))
209 + {
210 + if ("" != newArg)
211 + {
212 + newArgs.Add(newArg);
213 + newArg = null;
214 + }
215 +
216 + continue;
217 + }
218 +
219 + // if we're escaping a quote
220 + if ('\\' == line[j] && '"' == line[j])
221 + {
222 + ++j;
223 + }
224 + else if ('"' == line[j]) // if we've hit a new quote
225 + {
226 + betweenQuotes = !betweenQuotes;
227 + continue;
228 + }
229 +
230 + newArg = String.Concat(newArg, line[j]);
231 + }
232 + if ("" != newArg)
233 + {
234 + newArgs.Add(newArg);
235 + }
236 + }
237 + string[] ar = (string[])newArgs.ToArray(typeof(string));
238 + this.ParseCommandLine(ar);
239 + }
240 + }
241 + else if (null == this.sourceFile)
242 + {
243 + this.sourceFile = arg;
244 + }
245 + else if (null == this.destClassFile)
246 + {
247 + this.destClassFile = arg;
248 + }
249 + else if (null == this.destResourcesFile)
250 + {
251 + this.destResourcesFile = arg;
252 + }
253 + else
254 + {
255 + throw new ArgumentException(String.Format("Unknown argument '{0}'.", arg));
256 + }
257 + }
258 + }
259 + }
260 + }
261 +}
src/WixBuildTools.MsgGen/WixBuildTools.MsgGen.csproj new
+22
@@ -0,0 +1,22 @@
1 +<Project Sdk="Microsoft.NET.Sdk">
2 +
3 + <PropertyGroup>
4 + <OutputType>Exe</OutputType>
5 + <TargetFramework>net461</TargetFramework>
6 + <IsTool>true</IsTool>
7 + </PropertyGroup>
8 +
9 + <ItemGroup>
10 + <Content Include="build\WixBuildTools.MsgGen.targets" PackagePath="build\" />
11 + <Content Include="buildCrossTargeting\WixBuildTools.MsgGen.targets" PackagePath="buildCrossTargeting\" />
12 + </ItemGroup>
13 +
14 + <ItemGroup>
15 + <EmbeddedResource Include="Xsd\messages.xsd" />
16 + </ItemGroup>
17 +
18 + <ItemGroup>
19 + <PackageReference Include="Nerdbank.GitVersioning" Version="2.0.37-beta" PrivateAssets="all" />
20 + </ItemGroup>
21 +
22 +</Project>
src/WixBuildTools.MsgGen/Xsd/messages.xsd new
+101
@@ -0,0 +1,101 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<!-- 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. -->
3 +
4 +
5 +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
6 + targetNamespace="http://schemas.microsoft.com/genmsgs/2004/07/messages"
7 + xmlns="http://schemas.microsoft.com/genmsgs/2004/07/messages">
8 + <xs:annotation>
9 + <xs:documentation>
10 + Schema for describing any kind of messages.
11 + </xs:documentation>
12 + </xs:annotation>
13 +
14 + <xs:element name="Messages">
15 + <xs:complexType>
16 + <xs:sequence maxOccurs="unbounded">
17 + <xs:element ref="Class"/>
18 + </xs:sequence>
19 + <xs:attribute name="Namespace" type="xs:string" use="required">
20 + <xs:annotation><xs:documentation>Namespace of the generated class.</xs:documentation></xs:annotation>
21 + </xs:attribute>
22 + <xs:attribute name="Resources" type="xs:string" use="required">
23 + <xs:annotation><xs:documentation>Resources stream for messages. Will get namespace prepended to it.</xs:documentation></xs:annotation>
24 + </xs:attribute>
25 + </xs:complexType>
26 + </xs:element>
27 +
28 + <xs:element name="Class">
29 + <xs:complexType>
30 + <xs:sequence minOccurs="0" maxOccurs="unbounded">
31 + <xs:element ref="Message"/>
32 + </xs:sequence>
33 + <xs:attribute name="Name" type="xs:string" use="required">
34 + <xs:annotation><xs:documentation>Name of the generated class.</xs:documentation></xs:annotation>
35 + </xs:attribute>
36 + <xs:attribute name="ContainerName" type="xs:string" use="required">
37 + <xs:annotation><xs:documentation>Name of the generated container class.</xs:documentation></xs:annotation>
38 + </xs:attribute>
39 + <xs:attribute name="BaseContainerName" type="xs:string" use="required">
40 + <xs:annotation><xs:documentation>Name of the base container class.</xs:documentation></xs:annotation>
41 + </xs:attribute>
42 + <xs:attribute name="Level" type="MessageLevelType">
43 + <xs:annotation><xs:documentation>Optional message level for this container class and derivative classes.</xs:documentation></xs:annotation>
44 + </xs:attribute>
45 + </xs:complexType>
46 + </xs:element>
47 +
48 + <xs:element name="Message">
49 + <xs:complexType>
50 + <xs:sequence maxOccurs="unbounded">
51 + <xs:element ref="Instance"/>
52 + </xs:sequence>
53 + <xs:attribute name="Id" type="xs:string" use="required">
54 + <xs:annotation><xs:documentation>Name of the message type.</xs:documentation></xs:annotation>
55 + </xs:attribute>
56 + <xs:attribute name="Number" type="xs:integer" use="required">
57 + <xs:annotation><xs:documentation>Override the number for this message type.</xs:documentation></xs:annotation>
58 + </xs:attribute>
59 + <xs:attribute name="SourceLineNumbers" type="YesNoType">
60 + <xs:annotation><xs:documentation>Associate SourceLineNumbers with this message. The default value is "yes".</xs:documentation></xs:annotation>
61 + </xs:attribute>
62 + </xs:complexType>
63 + </xs:element>
64 +
65 + <xs:element name="Instance">
66 + <xs:complexType mixed="true">
67 + <xs:sequence minOccurs="0" maxOccurs="unbounded">
68 + <xs:element ref="Parameter"/>
69 + </xs:sequence>
70 + </xs:complexType>
71 + </xs:element>
72 +
73 + <xs:element name="Parameter">
74 + <xs:complexType>
75 + <xs:attribute name="Type" type="xs:string" use="required">
76 + <xs:annotation><xs:documentation>Type of the parameter.</xs:documentation></xs:annotation>
77 + </xs:attribute>
78 + <xs:attribute name="Name" type="xs:string" use="required">
79 + <xs:annotation><xs:documentation>Name of the parameter.</xs:documentation></xs:annotation>
80 + </xs:attribute>
81 + </xs:complexType>
82 + </xs:element>
83 +
84 + <xs:simpleType name="YesNoType">
85 + <xs:annotation><xs:documentation>Values of this type will either be "yes" or "no".</xs:documentation></xs:annotation>
86 + <xs:restriction base="xs:NMTOKEN">
87 + <xs:enumeration value="no"/>
88 + <xs:enumeration value="yes"/>
89 + </xs:restriction>
90 + </xs:simpleType>
91 +
92 + <xs:simpleType name="MessageLevelType">
93 + <xs:annotation><xs:documentation>The message level for this message which corresponds to the WixToolset.MessageLevel enumeration.</xs:documentation></xs:annotation>
94 + <xs:restriction base="xs:NMTOKEN">
95 + <xs:enumeration value="Verbose"/>
96 + <xs:enumeration value="Information"/>
97 + <xs:enumeration value="Warning"/>
98 + <xs:enumeration value="Error"/>
99 + </xs:restriction>
100 + </xs:simpleType>
101 +</xs:schema>
src/WixBuildTools.MsgGen/build/WixBuildTools.MsgGen.targets new
+102
@@ -0,0 +1,102 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<!-- 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. -->
3 +
4 +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
5 + <PropertyGroup>
6 + <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
7 + </PropertyGroup>
8 +
9 + <ItemGroup>
10 + <!--Provide support for setting type (BuildAction) from VS-->
11 + <AvailableItemName Include="MsgGenSource" />
12 + </ItemGroup>
13 +
14 + <PropertyGroup>
15 + <MsgGenPath Condition=" '$(MsgGenPath)'=='' ">$(MSBuildThisFileDirectory)..\tools\</MsgGenPath>
16 + </PropertyGroup>
17 +
18 + <!--
19 + ================================================================================================
20 + MsgGen
21 +
22 + Generates a .cs class file and a .resx file from an XML file.
23 +
24 + [IN]
25 + @(MsgGenSource) - The items to run through the MsgGen tool.
26 +
27 + [OUT]
28 + $(IntermediateOutputPath)%(Filename).cs - The generated .cs files to include in the compilation.
29 + $(IntermediateOutputPath)%(MsgGenSource.ResourcesLogicalName) - The generated .resources file to embed in the assembly.
30 + ================================================================================================
31 + -->
32 + <PropertyGroup>
33 + <MsgGenDependsOn>
34 + PrepareMsgGen
35 + </MsgGenDependsOn>
36 + <PrepareResourcesDependsOn>
37 + MsgGen;
38 + $(PrepareResourcesDependsOn)
39 + </PrepareResourcesDependsOn>
40 + </PropertyGroup>
41 + <Target
42 + Name="MsgGen"
43 + BeforeTargets="PrepareResources"
44 + DependsOnTargets="$(MsgGenDependsOn)"
45 + Condition=" '@(MsgGenSource)' != '' "
46 + Inputs="@(MsgGenSource)"
47 + Outputs="$(IntermediateOutputPath)%(MsgGenSource.Filename).cs;
48 + $(IntermediateOutputPath)%(MsgGenSource.ResourcesLogicalName)">
49 +
50 + <Exec Command="&quot;$(MsgGenPath)WixBuildTools.MsgGen.exe&quot; -nologo &quot;%(MsgGenSource.FullPath)&quot; &quot;$(MsgGenCsFile)&quot; &quot;$(MsgGenResourcesFile)&quot;"
51 + Outputs="$(MsgGenCsFile);$(MsgGenResourcesFile)" />
52 +
53 + <ItemGroup>
54 + <!-- This will tell MSBuild to clean up the .cs and .resources file during a Clean build -->
55 + <FileWrites Include="$(MsgGenCsFile);$(MsgGenResourcesFile)" />
56 + </ItemGroup>
57 + </Target>
58 +
59 + <!--
60 + ================================================================================================
61 + PrepareMsgGen
62 +
63 + Creates properties and Include items for MsgGen. This must be separate from the MsgGen target
64 + to workaround an MSBuild bug: AdditionalMetadata is ignored when the target is up-to-date.
65 +
66 + ================================================================================================
67 + -->
68 + <Target
69 + Name="PrepareMsgGen"
70 + Condition=" '@(MsgGenSource)' != '' ">
71 +
72 + <CreateProperty Value="$(IntermediateOutputPath)%(MsgGenSource.Filename).cs">
73 + <Output TaskParameter="Value" PropertyName="MsgGenCsFile" />
74 + </CreateProperty>
75 +
76 + <CreateProperty
77 + Value="$(IntermediateOutputPath)%(MsgGenSource.ResourcesLogicalName)"
78 + Condition=" '%(MsgGenSource.ResourcesLogicalName)' != '' ">
79 +
80 + <Output TaskParameter="Value" PropertyName="MsgGenResourcesFile" />
81 + </CreateProperty>
82 +
83 + <!-- Add the generated .cs file to the list of source files to compile -->
84 + <CreateItem
85 + Include="$(MsgGenCsFile)"
86 + AdditionalMetadata="Link=%(MsgGenCsFile.Filename)%(MsgGenCsFile.Extension)">
87 +
88 + <Output TaskParameter="Include" ItemName="Compile" />
89 + </CreateItem>
90 +
91 + <!-- Add the generated .resources file to the list of resources to embed -->
92 + <CreateItem
93 + Include="$(MsgGenResourcesFile)"
94 + AdditionalMetadata="Link=%(MsgGenResourcesFile.Filename)%(MsgGenResourcesFile.Extension);
95 + LogicalName=%(MsgGenSource.ResourcesLogicalName)"
96 + Condition=" '$(MsgGenResourcesFile)' != '' ">
97 +
98 + <Output TaskParameter="Include" ItemName="EmbeddedResource" />
99 + </CreateItem>
100 + </Target>
101 +
102 +</Project>
src/WixBuildTools.MsgGen/buildCrossTargeting/WixBuildTools.MsgGen.targets new
+6
@@ -0,0 +1,6 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<!-- 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. -->
3 +
4 +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
5 + <Import Project="..\build\WixBuildTools.MsgGen.targets" />
6 +</Project>