2008-11-06 9 views
12

¿Hay alguna herramienta para generar WiX XML con un archivo .reg?¿Cómo generar WiX XML desde un archivo .reg?


En 2.0, que se supone que es capaz de ejecutar de sebo para generar XML del registro:

tallow -r my.reg 

Por lo que vale la pena, la versión de sebo que tengo está produciendo XML vacía.

En 3.0, el sebo ha sido reemplazado por calor, pero no puedo encontrar la manera de hacerlo para producir un archivo .reg.

¿Hay alguna manera de hacer esto en 3.0?

+0

Hay una actualización de 2012 a esta pregunta: [Adición de un archivo .reg al registro WIX - desbordamiento de pila] (https://stackoverflow.com/questions/11988805/adding-a -reg-file-to-registry-wix/11988983 # 11988983) con una respuesta más agradable :) – Wolf

Respuesta

11

No pude encontrar una herramienta, así que hice una.

El código fuente puede no ser elegante, pero parece que funciona:

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

¡Buen trabajo! Aunque no lo intenté ... Copiaste la cadena "clave" en ArgumentNullException para obtener el valor;) – CheGueVerra

+0

Buena captura, gracias. –

+0

+1. Lo intenté y funcionó para lo que necesitaba que hiciera. – Brian

1

He intentado tallow.exe (versión 2.0.5805) de la última versión estable Wix 2 y funcionó bien para mí.

tallow -reg my.reg 

Esto generará el marcado usando Wix 2 "Registro" etiqueta que era obsoleto en Wix 3. Entonces usted tiene que copiar el resultado en un archivo de origen Wix y ejecutar WixCop utilidad para convertir Wix 2 marcado a Wix 3:

wixcop my.wxs -f 
5

Aquí está el código fuente de la utilidad que genera Wix 3 de marcado (incluyendo binaria , dword y valores del registro de cadena múltiple):

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 
    } 
} 
+0

¿Fue esta una incorporación reciente a Wix3? ¿Esto ahora está en celo? –

+1

Funciona bien y me gusta el formato de salida. Sin embargo, está cortando el último carácter de los valores. He cambiado 'actualValue = rawValue.Substring (1, rawValue.Longitud - 2); ' a 'actualValue = rawValue.Substring (1, rawValue.Length - 1);' en la línea 244 y está arreglado. – AndrewS

+0

+1. Maneja los valores de Multistring mejor que el código de Adam. – Brian

1

Este código funciona bien, pero si usted tiene un valor cadena vacía en el archivo de registro que está importando, un error de excepción se tira. Es posible que desee actualizar la sección ParseRegistryValue en consecuencia.

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