代码之家  ›  专栏  ›  技术社区  ›  Adam Tegen

如何从.reg文件生成WiX XML?

  •  13
  • Adam Tegen  · 技术社区  · 16 年前


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

    tallow -r my.reg 
    

    值得一提的是,我拥有的牛油版本正在生成空XML。

    在3.0中,牛脂已被加热所取代,但我不知道如何让它从.reg文件生成输出。

    6 回复  |  直到 16 年前
        1
  •  12
  •   Adam Tegen    16 年前

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

    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]);
            }
        }
    }
    
        2
  •  5
  •   YONDERBOI    15 年前

    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
        }
    }
    
        3
  •  5
  •   Community noseratio    7 年前

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

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

        4
  •  1
  •   YONDERBOI    15 年前

    我试过了 从最近的马厩 Wix 2 释放,这对我来说很好。

    tallow -reg my.reg
    

    那是什么标签 在Wix 3中已弃用 . 然后您必须将输出复制到wix源文件并执行 WixCop

    wixcop my.wxs -f
    
        5
  •  1
  •       15 年前

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

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

    来自WIX4.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