deployment - metaetiqueta - ¿Cómo generar WiX XML desde un archivo.reg?
metaetiqueta wix (5)
No pude encontrar una herramienta, así que hice una.
El código fuente puede no ser elegante, pero parece funcionar:
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]);
}
}
}
¿Hay alguna herramienta para generar WiX XML con un archivo .reg?
En 2.0, se suponía que podías ejecutar sebo para generar el registro XML:
tallow -r my.reg
Por lo que vale, la versión de sebo que tengo está produciendo XML vacío.
En 3.0, sebo ha sido reemplazado por calor, pero no puedo encontrar la forma de hacerlo para producir un archivo .reg.
¿Hay alguna manera de hacer esto en 3.0?
Aquí está el código fuente de la utilidad que genera el marcado Wix 3 (incluidos los valores de registro binario, dword y multicadena):
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
}
}
He intentado con tallow.exe (versión 2.0.5805) desde la última versión estable de Wix 2 y funcionó bien para mí.
tallow -reg my.reg
Esto generará el marcado utilizando la etiqueta "Registro" de Wix 2 que quedó obsoleta en Wix 3 . Luego, debe copiar la salida en un archivo fuente wix y ejecutar la utilidad WixCop para convertir el marcado Wix 2 a Wix 3:
wixcop my.wxs -f
Este código funciona bien, pero si tiene un valor de cadena vacío en el archivo de registro que está importando, se genera un error de excepción. 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 = "";
}
}
Ahora está integrado en Wix: Heat.exe
- Herramienta de cosecha.
https://.com/a/11988983/483588