【问题标题】:How to generate WiX XML from a .reg file?如何从 .reg 文件生成 WiX XML?
【发布时间】:2010-09-21 03:07:45
【问题描述】:

是否有工具可以在给定 .reg 文件的情况下生成 WiX XML?


在 2.0 中,您应该能够运行 tallow 来生成注册表 XML:

tallow -r my.reg 

不管怎样,我拥有的tallow 版本正在生成空的XML。

在 3.0 中,tallow 已被替换为 heat,但我不知道如何让它从 .reg 文件中生成输出。

有没有办法在 3.0 中做到这一点?

【问题讨论】:

标签: deployment installation wix windows-installer


【解决方案1】:

来自 Wix 4.0

C:\Program Files (x86)\WiX Toolset v4.0\bin>heat /? | find /i "reg"
   reg      harvest a .reg file
   -sreg    suppress registry harvesting

使用,其中 regfile.reg 是注册表输入文件,fragment.xml 是要生成的输出文件。

heat reg regfile.reg -o fragment.xml

【讨论】:

    【解决方案2】:

    现在它已内置到 Wix 中:Heat.exe - 收集工具。

    https://stackoverflow.com/a/11988983/483588

    【讨论】:

      【解决方案3】:

      此代码运行良好,但如果您正在导入的注册表文件中有一个空字符串值,则会引发异常错误。您可能需要相应地更新 ParseRegistryValue 部分。

             if (rawValue.IndexOf("\"") != -1)
              {
                  valueType = "string";
                  if (rawValue.Length > 1)
                  {
                      actualValue = rawValue.Substring(1, rawValue.Length - 2);
                  }
                  else
                  {
                      actualValue = "";
                  }
              }
      

      【讨论】:

        【解决方案4】:

        这是生成 Wix 3 标记的实用程序的源代码(包括二进制、双字和多字符串注册表值):

        using System;
        using System.Globalization;
        using System.IO;
        using System.Reflection;
        using System.Security.Cryptography;
        using System.Text;
        using System.Text.RegularExpressions;
        using System.Xml;
        
        namespace AbsReg2Wix
        {
            public class Program
            {
                #region Constants
        
                private const string NS_URI = "http://schemas.microsoft.com/wix/2006/wi";
                private const string RegEditorVersionPattern = @"Windows\sRegistry\sEditor\sVersion\s(?<RegEditorVersion>.*)";
                private const string RegKeyPattern = @"\[(?<RegistryHive>[^\\]*)\\(?<RegistryKey>.*)\]";
                private const string RegNameValuePattern = "\\\"(?<Name>.*)\\\"=(?<Value>\\\"?[^\\\\\\\"]*)(?<MultiLine>\\\\?)";
                private const RegexOptions DefaultRegexOptions = RegexOptions.Multiline |
                                                                 RegexOptions.IgnorePatternWhitespace |
                                                                 RegexOptions.CultureInvariant;
                #endregion
        
                #region Methods
        
                /// <summary>
                /// Main applciation entry point
                /// </summary>
                /// <param name="args">The args.</param>
                private static void Main(string[] args)
                {
                    if (args.Length != 4)
                    {
                        PrintUsageInstructions();
                        return;
                    }
        
                    if (File.Exists(args[1]))
                    {
                        ConvertRegistryFileToWix(args[1], args[3]);
        
                        Console.WriteLine("Successfully completed conversion.");
                        Console.WriteLine("Press any key to continue...");
                        Console.ReadKey();
                    }
                    else
                    {
                        Console.WriteLine(@"Input file {0} not found.", args[1]);
                    }
                }
        
                /// <summary>
                /// Prints the usage instructions.
                /// </summary>
                private static void PrintUsageInstructions()
                {
                    Console.WriteLine("Syntax: AbsReg2Wix.exe /in <Input File (.reg)> /out <Output File>");
                }
        
                /// <summary>
                /// Convert a .reg file into a .wsx file
                /// </summary>
                /// <param name="inputPath">The input path.</param>
                /// <param name="outputPath">The output path.</param>
                private static void ConvertRegistryFileToWix(string inputPath, string outputPath)
                {
                    try
                    {
                        using (var reader = new StreamReader(inputPath))
                        {
                            string regEditorVersion = string.Empty;
                            bool isRegEditorVersionFound = false;
        
                            // Initialize Regex 
                            var regEditorVersionRegex = new Regex(RegEditorVersionPattern, DefaultRegexOptions);
                            var regKeyRegex = new Regex(RegKeyPattern, DefaultRegexOptions);
                            var regNameValueRegex = new Regex(RegNameValuePattern, DefaultRegexOptions);
        
                            // Create xml document for output
                            var xDoc = new XmlDocument();
                            xDoc.AppendChild(xDoc.CreateProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""));
                            xDoc.AppendChild(xDoc.CreateComment(
                                                 string.Format(
                                                     "{0}Following code was generated by AbsReg2Wix tool.{0}Tool Version: {1}{0}Date: {2}{0}Command Line: {3}\n",
                                                     "\n\t", Assembly.GetExecutingAssembly().GetName().Version,
                                                     DateTime.Now.ToString("F"),
                                                     Environment.CommandLine)));
        
                            XmlElement includeElement = xDoc.CreateElement("Include", NS_URI);
                            XmlElement componentElement = null,
                                       regKeyElement = null,
                                       registryValueElement = null;
        
                            bool multiLine = false;
                            var rawValueBuilder = new StringBuilder();
        
                            while (!reader.EndOfStream)
                            {
                                string regFileLine = reader.ReadLine().Trim();
        
                                if (!isRegEditorVersionFound)
                                {
                                    var regEditorVersionMatch = regEditorVersionRegex.Match(regFileLine);
        
                                    if (regEditorVersionMatch.Success)
                                    {
                                        regEditorVersion = regEditorVersionMatch.Groups["RegEditorVersion"].Value;
                                        includeElement.AppendChild(
                                            xDoc.CreateComment("Registry Editor Version: " + regEditorVersion));
                                        isRegEditorVersionFound = true;
                                    }
                                }
        
                                var regKeyMatch = regKeyRegex.Match(regFileLine);
        
                                // Registry Key line found
                                if (regKeyMatch.Success)
                                {
                                    if (componentElement != null)
                                    {
                                        componentElement.AppendChild(regKeyElement);
                                        includeElement.AppendChild(componentElement);
                                    }
        
                                    componentElement = xDoc.CreateElement("Component", NS_URI);
        
                                    var idAttr = xDoc.CreateAttribute("Id");
                                    idAttr.Value = "Comp_" + GetMD5HashForString(regFileLine);
                                    componentElement.Attributes.Append(idAttr);
        
                                    var guidAttr = xDoc.CreateAttribute("Guid");
                                    guidAttr.Value = Guid.NewGuid().ToString();
                                    componentElement.Attributes.Append(guidAttr);
        
                                    regKeyElement = xDoc.CreateElement("RegistryKey", NS_URI);
        
                                    var hiveAttr = xDoc.CreateAttribute("Root");
                                    hiveAttr.Value = GetShortHiveName(regKeyMatch.Groups["RegistryHive"].Value);
                                    regKeyElement.Attributes.Append(hiveAttr);
        
                                    var keyAttr = xDoc.CreateAttribute("Key");
                                    keyAttr.Value = regKeyMatch.Groups["RegistryKey"].Value;
                                    regKeyElement.Attributes.Append(keyAttr);
        
                                    var actionAttr = xDoc.CreateAttribute("Action");
                                    actionAttr.Value = "createAndRemoveOnUninstall";
                                    regKeyElement.Attributes.Append(actionAttr);
                                }
        
                                var regNameValueMatch = regNameValueRegex.Match(regFileLine);
        
                                // Registry Name/Value pair line found
                                if (regNameValueMatch.Success)
                                {
                                    registryValueElement = xDoc.CreateElement("RegistryValue", NS_URI);
        
                                    var nameAttr = xDoc.CreateAttribute("Name");
                                    nameAttr.Value = regNameValueMatch.Groups["Name"].Value;
                                    registryValueElement.Attributes.Append(nameAttr);
        
                                    var actionAttr = xDoc.CreateAttribute("Action");
                                    actionAttr.Value = "write";
                                    registryValueElement.Attributes.Append(actionAttr);
        
                                    if (string.IsNullOrEmpty(regNameValueMatch.Groups["MultiLine"].Value))
                                    {
                                        string valueType, actualValue;
        
                                        ParseRegistryValue(regNameValueMatch.Groups["Value"].Value, out valueType,
                                                           out actualValue);
        
                                        var typeAttr = xDoc.CreateAttribute("Type");
                                        typeAttr.Value = valueType;
                                        registryValueElement.Attributes.Append(typeAttr);
        
                                        var valueAttr = xDoc.CreateAttribute("Value");
                                        valueAttr.Value = actualValue;
                                        registryValueElement.Attributes.Append(valueAttr);
                                        regKeyElement.AppendChild(registryValueElement);
                                    }
                                    else
                                    {
                                        multiLine = true;
                                        rawValueBuilder.Append(regNameValueMatch.Groups["Value"].Value
                                                                   .Replace("\\", string.Empty));
                                    }
                                }
                                else if (multiLine)
                                {
                                    if (regFileLine.IndexOf("\\") != -1)
                                    {
                                        rawValueBuilder.Append(regFileLine.Replace("\\", string.Empty));
                                    }
                                    else
                                    {
                                        rawValueBuilder.Append(regFileLine);
        
                                        string valueType, actualValue;
                                        ParseRegistryValue(rawValueBuilder.ToString(), out valueType, out actualValue);
        
                                        var typeAttr = xDoc.CreateAttribute("Type");
                                        typeAttr.Value = valueType;
                                        registryValueElement.Attributes.Append(typeAttr);
        
                                        var valueAttr = xDoc.CreateAttribute("Value");
                                        valueAttr.Value = actualValue;
                                        registryValueElement.Attributes.Append(valueAttr);
                                        regKeyElement.AppendChild(registryValueElement);
        
                                        rawValueBuilder.Remove(0, rawValueBuilder.Length);
                                        multiLine = false;
                                    }
                                }
                            }
        
                            if (componentElement != null)
                            {
                                componentElement.AppendChild(regKeyElement);
                                includeElement.AppendChild(componentElement);
                            }
        
                            xDoc.AppendChild(includeElement);
                            xDoc.Save(outputPath);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
        
                /// <summary>
                /// Parses the registry value.
                /// </summary>
                /// <param name="rawValue">The raw value.</param>
                /// <param name="valueType">Type of the value.</param>
                /// <param name="actualValue">The actual value.</param>
                private static void ParseRegistryValue(string rawValue, out string valueType, out string actualValue)
                {
                    if (rawValue.IndexOf("\"") != -1)
                    {
                        valueType = "string";
                        actualValue = rawValue.Substring(1, rawValue.Length - 2);
                    }
                    else if (rawValue.IndexOf("dword:") != -1)
                    {
                        valueType = "integer";
                        actualValue = rawValue.Replace("dword:", string.Empty);
                    }
                    else if (rawValue.IndexOf("hex:") != -1)
                    {
                        valueType = "binary";
                        actualValue = rawValue.Replace("hex:", string.Empty)
                                              .Replace(",", string.Empty)
                                              .ToUpper();
                    }
                    else if (rawValue.IndexOf("hex(7):") != -1)
                    {
                        valueType = "multiString";
        
                        string[] hexStrings = rawValue.Replace("hex(7):", string.Empty).Split(',');
                        var bytes = new byte[hexStrings.Length];
        
                        for (int i = 0; i < hexStrings.Length; i++)
                        {
                            bytes[i] = byte.Parse(hexStrings[i], NumberStyles.HexNumber);
                        }
        
                        actualValue = Encoding.Unicode.GetString(bytes).Replace("\0", "[~]");
                    }
                    else
                    {
                        valueType = "string";
                        actualValue = rawValue;
                    }
                }
        
                /// <summary>
                /// Gets the short name of the registry hive.
                /// </summary>
                /// <param name="fullHiveName">Full name of the hive.</param>
                /// <returns></returns>
                private static string GetShortHiveName(string fullHiveName)
                {
                    switch (fullHiveName)
                    {
                        case "HKEY_LOCAL_MACHINE":
                            return "HKLM";
                        case "HKEY_CLASSES_ROOT":
                            return "HKCR";
                        case "HKEY_USERS":
                            return "HKU";
                        case "HKEY_CURRENT_USER":
                            return "HKCU";
                        default:
                            throw new ArgumentException(string.Format("Registry Hive unsupported by Wix: {0}.",
                                fullHiveName));
                    }
                }
        
                /// <summary>
                /// Gets the MD5 hash for string.
                /// </summary>
                /// <param name="inputString">The input string.</param>
                /// <returns></returns>
                private static string GetMD5HashForString(string inputString)
                {
                    MD5 hashAlg = MD5.Create();
                    byte[] originalInBytes = Encoding.ASCII.GetBytes(inputString);
                    byte[] hashedOriginal = hashAlg.ComputeHash(originalInBytes);
        
                    String outputString = Convert.ToBase64String(hashedOriginal)
                            .Replace("/", "aa")
                            .Replace("+", "bb")
                            .Replace("=", "cc");
        
                    return outputString;
                }
        
                #endregion
            }
        }
        

        【讨论】:

        • 这是最近添加到 Wix3 的吗?现在是不是很热?
        • 效果很好,我喜欢输出格式。然而,它正在切断最后一个字符的值。我改变了'actualValue = rawValue.Substring(1, rawValue.Length - 2);'到 'actualValue = rawValue.Substring(1, rawValue.Length - 1);'在第 244 行,它是固定的。
        【解决方案5】:

        我尝试了最新稳定版 Wix 2 中的 tallow.exe(版本 2.0.5805),它对我来说效果很好。

        tallow -reg my.reg
        

        这将使用Wix 2 “注册表”标签生成标记,该标签在Wix 3中被弃用。然后您必须将输出复制到 wix 源文件并执行 WixCop 实用程序将 Wix 2 标记转换为 Wix 3:

        wixcop my.wxs -f
        

        【讨论】:

          【解决方案6】:

          我找不到工具,所以我做了一个。

          源代码可能不优雅,但似乎可以工作:

          using System;
          using System.Collections.Generic;
          using System.Text;
          using System.IO;
          using System.Xml;
          using System.Text.RegularExpressions;
          
          namespace Reg2Wix
          {
              class Program
              {
                  static void PrintUsage()
                  {
                      Console.WriteLine("reg2wix <input file> <output file>");
                  }
          
                  /// <summary>
                  /// Parse the hive out of a registry key
                  /// </summary>
                  /// <param name="keyWithHive"></param>
                  /// <param name="hive"></param>
                  /// <param name="key"></param>
                  static void ParseKey(string keyWithHive, out string hive, out string key)
                  {
                      if (keyWithHive == null)
                      {
                          throw new ArgumentNullException("keyWithHive");
                      }
                      if (keyWithHive.StartsWith("HKEY_LOCAL_MACHINE\\"))
                      {
                          hive = "HKLM";
                          key = keyWithHive.Substring(19);
                      }
                      else if (keyWithHive.StartsWith("HKEY_CLASSES_ROOT\\"))
                      {
                          hive = "HKCR";
                          key = keyWithHive.Substring(18);
                      }
                      else if (keyWithHive.StartsWith("HKEY_USERS\\"))
                      {
                          hive = "HKU";
                          key = keyWithHive.Substring(11);
                      }
                      else if (keyWithHive.StartsWith("HKEY_CURRENT_USER\\"))
                      {
                          hive = "HKCU";
                          key = keyWithHive.Substring(18);
                      }
                      else
                      {
                          throw new ArgumentException();
                      }        
                  }
          
                  /// <summary>
                  /// Write a WiX RegistryValue element for the specified key, name, and value
                  /// </summary>
                  /// <param name="writer"></param>
                  /// <param name="key"></param>
                  /// <param name="name"></param>
                  /// <param name="value"></param>
                  static void WriteRegistryValue(XmlWriter writer, string key, string name, string value)
                  {
                      if (writer == null)
                      {
                          throw new ArgumentNullException("writer");
                      }
                      if (key == null)
                      {
                          throw new ArgumentNullException("key");
                      }
                      if (value == null)
                      {
                          throw new ArgumentNullException("value");
                      }
          
                      string hive;
                      string keyPart;
                      ParseKey(key, out hive, out keyPart);
          
                      writer.WriteStartElement("RegistryValue");
          
                      writer.WriteAttributeString("Root", hive);
                      writer.WriteAttributeString("Key", keyPart);
                      if (!String.IsNullOrEmpty(name))
                      {
                          writer.WriteAttributeString("Name", name);
                      }
                      writer.WriteAttributeString("Value", value);
                      writer.WriteAttributeString("Type", "string");
                      writer.WriteAttributeString("Action", "write");
          
                      writer.WriteEndElement();
                  }
          
                  /// <summary>
                  /// Convert a .reg file into an XML document
                  /// </summary>
                  /// <param name="inputReader"></param>
                  /// <param name="xml"></param>
                  static void RegistryFileToWix(TextReader inputReader, XmlWriter xml)
                  {
                      Regex regexKey = new Regex("^\\[([^\\]]+)\\]$");
                      Regex regexValue = new Regex("^\"([^\"]+)\"=\"([^\"]*)\"$");
                      Regex regexDefaultValue = new Regex("@=\"([^\"]+)\"$");
          
                      string currentKey = null;
          
                      string line;
                      while ((line = inputReader.ReadLine()) != null)
                      {
                          line = line.Trim();
                          Match match = regexKey.Match(line);                
                          if (match.Success)
                          {
                              //key track of the current key
                              currentKey = match.Groups[1].Value;
                          }
                          else 
                          {
                              //if we have a current key
                              if (currentKey != null)
                              {
                                  //see if this is an acceptable name=value pair
                                  match = regexValue.Match(line);
                                  if (match.Success)
                                  {
                                      WriteRegistryValue(xml, currentKey, match.Groups[1].Value, match.Groups[2].Value);
                                  }
                                  else
                                  {
                                      //see if this is an acceptable default value (starts with @)
                                      match = regexDefaultValue.Match(line);
                                      if (match.Success)
                                      {
                                          WriteRegistryValue(xml, currentKey, (string)null, match.Groups[1].Value);
                                      }
                                  }
                              }
                          }
                      }
                  }
          
                  /// <summary>
                  /// Convert a .reg file into a .wsx file
                  /// </summary>
                  /// <param name="inputPath"></param>
                  /// <param name="outputPath"></param>
                  static void RegistryFileToWix(string inputPath, string outputPath)
                  {
                      using (StreamReader reader = new StreamReader(inputPath))
                      {
                          using (XmlTextWriter writer = new XmlTextWriter(outputPath, Encoding.UTF8))
                          {
                              writer.Formatting = Formatting.Indented;
                              writer.Indentation = 3;
                              writer.IndentChar = ' ';
                              writer.WriteStartDocument();
                              writer.WriteStartElement("Component");
                              RegistryFileToWix(reader, writer);
                              writer.WriteEndElement();
                              writer.WriteEndDocument();
                          }
                      }
                  }
          
                  static void Main(string[] args)
                  {
                      if (args.Length != 2)
                      {
                          PrintUsage();
                          return;
                      }
                      RegistryFileToWix(args[0], args[1]);
                  }
              }
          }
          

          【讨论】:

          • 干得好!不过没有尝试过...您在 ArgumentNullException 中复制了字符串“key”作为值;)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-01-21
          • 1970-01-01
          • 2011-11-29
          • 2011-10-05
          • 2015-12-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多