13

给定 .reg 文件,是否有生成 WiX XML 的工具?


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

tallow -r my.reg 

对于它的价值,我拥有的动物脂版本正在生成空 XML。

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

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

4

6 回答 6

12

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

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

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]);
        }
    }
}
于 2008-11-06T21:49:55.820 回答
5

以下是生成 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
    }
}
于 2009-04-11T06:19:41.507 回答
5

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

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

于 2012-10-11T16:13:15.080 回答
1

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

tallow -reg my.reg

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

wixcop my.wxs -f
于 2009-04-11T06:07:31.770 回答
1

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

       if (rawValue.IndexOf("\"") != -1)
        {
            valueType = "string";
            if (rawValue.Length > 1)
            {
                actualValue = rawValue.Substring(1, rawValue.Length - 2);
            }
            else
            {
                actualValue = "";
            }
        }
于 2009-06-09T15:19:16.610 回答
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
于 2018-05-07T22:01:28.943 回答