![](/img/trans.png)
[英]My C# application is in a loop, how can i find the position in the code?
[英]How can I find the upgrade code for an installed application in C#?
我正在使用WIX 工具集中的 Windows Installer API 的 C# 包裝器。 我使用ProductInstallation
類來獲取有關已安裝產品的信息,例如產品代碼和產品名稱。
例如
此包裝器在內部使用MsiGetProductInfo函數。 不幸的是,此函數不會返回產品的升級代碼。
如何使用 C# 檢索已安裝應用程序的升級代碼?
我發現升級代碼存儲在以下注冊表位置。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes
注冊表項名稱是升級代碼,注冊表項值名稱是產品代碼。 我可以輕松提取這些值,但是代碼以不同的格式存儲。 紅圈是格式化后的升級代碼,藍圈是在regedit.exe
查看時格式化的產品代碼。
連字符從Guid
中剝離,然后完成一系列字符串反轉。 前 8 個字符被反轉,然后是接下來的 4 個,然后是接下來的 4 個,然后字符串的其余部分以 2 個字符為一組反轉。 通常,在反轉字符串時,我們需要注意確保正確處理控制和特殊字符( 請參閱此處的 Jon Skeet 的文章),但正如我們一樣,在這種情況下,處理Guid
字符串我們可以確信該字符串將被反轉正確。
下面是我用來從注冊表中提取已知產品代碼的升級代碼的完整代碼。
internal static class RegistryHelper
{
private const string UpgradeCodeRegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes";
private static readonly int[] GuidRegistryFormatPattern = new[] { 8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2 };
public static Guid? GetUpgradeCode(Guid productCode)
{
// Convert the product code to the format found in the registry
var productCodeSearchString = ConvertToRegistryFormat(productCode);
// Open the upgrade code registry key
var localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var upgradeCodeRegistryRoot = localMachine.OpenSubKey(UpgradeCodeRegistryKey);
if (upgradeCodeRegistryRoot == null)
return null;
// Iterate over each sub-key
foreach (var subKeyName in upgradeCodeRegistryRoot.GetSubKeyNames())
{
var subkey = upgradeCodeRegistryRoot.OpenSubKey(subKeyName);
if (subkey == null)
continue;
// Check for a value containing the product code
if (subkey.GetValueNames().Any(s => s.IndexOf(productCodeSearchString, StringComparison.OrdinalIgnoreCase) >= 0))
{
// Extract the name of the subkey from the qualified name
var formattedUpgradeCode = subkey.Name.Split('\\').LastOrDefault();
// Convert it back to a Guid
return ConvertFromRegistryFormat(formattedUpgradeCode);
}
}
return null;
}
private static string ConvertToRegistryFormat(Guid productCode)
{
return Reverse(productCode, GuidRegistryFormatPattern);
}
private static Guid ConvertFromRegistryFormat(string upgradeCode)
{
if (upgradeCode == null || upgradeCode.Length != 32)
throw new FormatException("Product code was in an invalid format");
upgradeCode = Reverse(upgradeCode, GuidRegistryFormatPattern);
return Guid.Parse(upgradeCode);
}
private static string Reverse(object value, params int[] pattern)
{
// Strip the hyphens
var inputString = value.ToString().Replace("-", "");
var returnString = new StringBuilder();
var index = 0;
// Iterate over the reversal pattern
foreach (var length in pattern)
{
// Reverse the sub-string and append it
returnString.Append(inputString.Substring(index, length).Reverse().ToArray());
// Increment our posistion in the string
index += length;
}
return returnString.ToString();
}
}
這是從 UpgradeCode 獲取 ProductCode 的相反方法。 可能對某人有用。
using Microsoft.Win32;
using System;
using System.IO;
using System.Linq;
using System.Text;
internal static class RegistryHelper
{
private const string UpgradeCodeRegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes";
private static readonly int[] GuidRegistryFormatPattern = new[] { 8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2 };
public static Guid? GetProductCode(Guid upgradeCode)
{
// Convert the product code to the format found in the registry
var productCodeSearchString = ConvertToRegistryFormat(upgradeCode);
// Open the upgrade code registry key
var upgradeCodeRegistryRoot = GetRegistryKey(Path.Combine(UpgradeCodeRegistryKey, productCodeSearchString));
if (upgradeCodeRegistryRoot == null)
return null;
var uninstallCode = upgradeCodeRegistryRoot.GetValueNames().FirstOrDefault();
if (string.IsNullOrEmpty(uninstallCode))
{
return null;
}
// Convert it back to a Guid
return ConvertFromRegistryFormat(uninstallCode);
}
private static string ConvertToRegistryFormat(Guid code)
{
return Reverse(code, GuidRegistryFormatPattern);
}
private static Guid ConvertFromRegistryFormat(string code)
{
if (code == null || code.Length != 32)
throw new FormatException("Product code was in an invalid format");
code = Reverse(code, GuidRegistryFormatPattern);
return Guid.Parse(code);
}
private static string Reverse(object value, params int[] pattern)
{
// Strip the hyphens
var inputString = value.ToString().Replace("-", "");
var returnString = new StringBuilder();
var index = 0;
// Iterate over the reversal pattern
foreach (var length in pattern)
{
// Reverse the sub-string and append it
returnString.Append(inputString.Substring(index, length).Reverse().ToArray());
// Increment our posistion in the string
index += length;
}
return returnString.ToString();
}
static RegistryKey GetRegistryKey(string registryPath)
{
var hklm64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var registryKey64 = hklm64.OpenSubKey(registryPath);
if (((bool?)registryKey64?.GetValueNames()?.Any()).GetValueOrDefault())
{
return registryKey64;
}
var hklm32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
return hklm32.OpenSubKey(registryPath);
}
}
InstallPackage 類有一個名為 LocalPackage 的屬性。 您可以使用它來查詢緩存在 C:\\Windows\\Installer 中的 MSI 數據庫,並獲取您可能想了解的任何信息。
只是評論以防萬一這在未來對任何人都派上用場!
如果您只有 GUID 或代碼可用,則可以使用以下站點在兩者之間進行轉換:
希望這可以節省一些未來的頭痛!
這是一種以注冊表格式(基本上只是原始字節表示)獲取 GUID 格式的更簡單的方法
首先是獲取原始字節:
var guidBytes = Guid.Parse(productCode).ToByteArray();
然后只需翻轉 BitConverter.ToString() 結果的字節序
var convertedString = String.Concat(BitConverter.ToString(guidBytes).Split('-').SelectMany(s => s.Reverse()));
這是您的助手,它以這樣的方式修改,它也適用於 .Net3.5 32 位應用程序。 它們需要特殊處理,因為 .net 3.5 不知道注冊表被分成 32 位和 64 位條目。 我的解決方案僅使用To64BitPath
來瀏覽其中的 64 位部分。 還有一個使用 DllImports 的很棒的教程: https : //www.rhyous.com/2011/01/24/how-read-the-64-bit-registry-from-a-32-bit-application-反之亦然/
class RegistryHelper
{
private const string UpgradeCodeRegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes";
private const string UninstallRegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
private static readonly int[] GuidRegistryFormatPattern = new[] { 8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2 };
public static string To64BitPath(string path)
{
return path.Replace("SOFTWARE\\Microsoft", "SOFTWARE\\WOW6432Node\\Microsoft");
}
private static RegistryKey GetLocalMachineRegistryKey(string path)
{
return RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, string.Empty).OpenSubKey(path);
}
public static IEnumerable<Guid> GetUpgradeCodes()
{
var list = new List<Guid>();
var key = GetRegistryKey(UpgradeCodeRegistryKey);
if (key != null)
{
list.AddRange(key.GetSubKeyNames().Select(ConvertFromRegistryFormat));
}
return list;
}
public static Guid? GetProductCode(Guid upgradeCode)
{
// Convert the product upgradeCode to the format found in the registry
var productCodeSearchString = ConvertToRegistryFormat(upgradeCode);
// Open the upgradeCode upgradeCode registry key
var upgradeCodeRegistryRoot = GetRegistryKey(Path.Combine(UpgradeCodeRegistryKey, productCodeSearchString));
if (upgradeCodeRegistryRoot == null)
return null;
var uninstallCode = upgradeCodeRegistryRoot.GetValueNames().FirstOrDefault();
if (string.IsNullOrEmpty(uninstallCode))
{
return null;
}
// Convert it back to a Guid
return ConvertFromRegistryFormat(uninstallCode);
}
public static string ConvertToRegistryFormat(Guid code)
{
return Reverse(code, GuidRegistryFormatPattern);
}
private static Guid ConvertFromRegistryFormat(string code)
{
if (code == null || code.Length != 32)
throw new FormatException("Product upgradeCode was in an invalid format");
code = Reverse(code, GuidRegistryFormatPattern);
return new Guid(code);
}
private static string Reverse(object value, params int[] pattern)
{
// Strip the hyphens
var inputString = value.ToString().Replace("-", "");
var returnString = new StringBuilder();
var index = 0;
// Iterate over the reversal pattern
foreach (var length in pattern)
{
// Reverse the sub-string and append it
returnString.Append(inputString.Substring(index, length).Reverse().ToArray());
// Increment our posistion in the string
index += length;
}
return returnString.ToString();
}
static RegistryKey GetRegistryKey(string registryPath)
{
var registryKey64 = GetLocalMachineRegistryKey(To64BitPath(registryPath));
if (((bool?)registryKey64?.GetValueNames()?.Any()).GetValueOrDefault())
{
return registryKey64;
}
return GetLocalMachineRegistryKey(registryPath);
}
public static Guid? GetUpgradeCode(Guid productCode)
{
var productCodeSearchString = ConvertToRegistryFormat(productCode);
var upgradeCodeRegistryRoot = GetRegistryKey(UpgradeCodeRegistryKey);
if (upgradeCodeRegistryRoot == null)
{
return null;
}
// Iterate over each sub-key
foreach (var subKeyName in upgradeCodeRegistryRoot.GetSubKeyNames())
{
var subkey = upgradeCodeRegistryRoot.OpenSubKey(subKeyName);
if (subkey == null)
continue;
// Check for a value containing the product upgradeCode
if (subkey.GetValueNames().Any(s => s.IndexOf(productCodeSearchString, StringComparison.OrdinalIgnoreCase) >= 0))
{
// Extract the name of the subkey from the qualified name
var formattedUpgradeCode = subkey.Name.Split('\\').LastOrDefault();
// Convert it back to a Guid
return ConvertFromRegistryFormat(formattedUpgradeCode);
}
}
return null;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.