2008-11-06 92 views
12

是否有一種工具可以生成給定.reg文件的WiX XML?如何從.reg文件生成WiX XML?


在2.0中,你應該能夠運行牛油生成註冊表XML:

tallow -r my.reg 

對於它的價值,牛油我的版本是生產空XML。

在3.0中,牛脂已被熱替代,但我無法弄清楚如何讓它從.reg文件產生輸出。

有沒有辦法在3.0中做到這一點?

+0

有一個2012更新到這個問題:添加一個.reg文件到註冊表維克斯 - 堆棧溢出(https://stackoverflow.com/questions/11988805/adding-a -reg-file-to-registry-wix/11988983#11988983)用更好的答案:) – Wolf 2016-08-05 10:18:47

回答

11

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

的源代碼可能不優雅,但它似乎工作:

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]); 
     } 
    } 
} 
+0

幹得好!雖然沒有嘗試過...您在ArgumentNullException中爲字符串「key」複製了值;) – CheGueVerra 2008-11-07 02:28:20

+0

好的,謝謝。 – 2008-11-07 15:37:53

1

我試過tallow.exe(版本2.0.5805)從最新的穩定維克斯2釋放它爲我工作得很好。

tallow -reg my.reg 

這將使用維克斯2 「註冊表」標籤,這是在3維克斯棄用生成標記。然後,你必須輸出複製到一個威克斯源文件並執行WixCop實用程序來維克斯2標記轉換爲維克斯3:

wixcop my.wxs -f 
5

這裏是實用程序的源代碼,生成維克斯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 
    } 
} 
1

此代碼工作得很好,但如果你有要導入註冊表文件中的一個空字符串值,異常錯誤被拋出。您可能需要相應地更新ParseRegistryValue部分。

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