问题描述
|
我有一个C#程序,必须在其中获取已安装的msi的产品代码。我只有msi名称作为输入。可以通过编程方式完成吗?
解决方法
有最快,最简单的方法-将WMI与条件查询字符串一起使用。
public string GetProductCode(string productName)
{
string query = string.Format(\"select * from Win32_Product where Name=\'{0}\'\",productName);
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
{
foreach (ManagementObject product in searcher.Get())
return product[\"IdentifyingNumber\"].ToString();
}
return null;
}
, 这个问题的答案有帮助吗?他们想获得产品名称,但是也许也适用于产品代码?
编辑
如果您没有MSI文件本身来访问数据库(如上述其他问题的链接所示),则可以尝试在以下注册表路径中搜索MSI文件的名称:
HKEY_CLASSES_ROOT\\Installer\\Products\\*\\SourceList
Products
分支下有很多条目。它们每个都是产品密钥。每个分支都应包含“ 3”节点,而该节点又应包含值“ 4”。该值保存MSI文件的名称。
所以我要做的是:
for each key in Products
{
open SourceList subkey
read PackageName value
if name equals my msi file name
{
return key-name formatted as GUID
}
}
, 这是我用来获取任何MSI的UninstallString
的代码。
private string GetUninstallString(string msiName)
{
Utility.WriteLog(\"Entered GetUninstallString(msiName) - Parameters: msiName = \" + msiName);
string uninstallString = string.Empty;
try
{
string path = \"SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Installer\\\\UserData\\\\S-1-5-18\\\\Products\";
RegistryKey key = Registry.LocalMachine.OpenSubKey(path);
foreach (string tempKeyName in key.GetSubKeyNames())
{
RegistryKey tempKey = key.OpenSubKey(tempKeyName + \"\\\\InstallProperties\");
if (tempKey != null)
{
if (string.Equals(Convert.ToString(tempKey.GetValue(\"DisplayName\")),msiName,StringComparison.CurrentCultureIgnoreCase))
{
uninstallString = Convert.ToString(tempKey.GetValue(\"UninstallString\"));
uninstallString = uninstallString.Replace(\"/I\",\"/X\");
uninstallString = uninstallString.Replace(\"MsiExec.exe\",\"\").Trim();
uninstallString += \" /quiet /qn\";
break;
}
}
}
return uninstallString;
}
catch (Exception ex)
{
throw new ApplicationException(ex.Message);
}
}
这样会得到如下结果:
MsiExec.exe /I{6BB09011-69E1-472F-ACAD-FA0E7DA3E2CE}
从该字符串中,您可以将大括号{}中的子字符串作为6BB09011-69E1-472F-ACAD-FA0E7DA3E2CE
。我希望这可能是产品代码。
, 此代码直接从MSI文件获取产品代码。因此,这允许在不安装文件的情况下读取代码。
class MsiHandle : SafeHandleMinusOneIsInvalid
{
public MsiHandle()
: base(true)
{ }
protected override bool ReleaseHandle()
{
return NativeMethods.MsiCloseHandle(handle) == 0;
}
}
class NativeMethods
{
const string MsiDll = \"Msi.dll\";
[DllImport(MsiDll,CharSet = CharSet.Unicode,ExactSpelling = true)]
public extern static uint MsiOpenPackageW(string szPackagePath,out MsiHandle product);
[DllImport(MsiDll,ExactSpelling=true)]
public extern static uint MsiCloseHandle(IntPtr hAny);
[DllImport(MsiDll,ExactSpelling = true)]
static extern uint MsiGetProductPropertyW(MsiHandle hProduct,string szProperty,StringBuilder value,ref int length);
[DllImport(MsiDll,ExactSpelling = true)]
public static extern int MsiSetInternalUI(int value,IntPtr hwnd);
public static uint MsiGetProductProperty(MsiHandle hProduct,out string value)
{
StringBuilder sb = new StringBuilder(1024);
int length = sb.Capacity;
uint err;
value = null;
if(0 == (err = MsiGetProductPropertyW(hProduct,szProperty,sb,ref length)))
{
sb.Length = length;
value = sb.ToString();
return 0;
}
return err;
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static int Main(string[] args)
{
string msiFile = args[0];
NativeMethods.MsiSetInternalUI(2,IntPtr.Zero); // Hide all UI. Without this you get a MSI dialog
MsiHandle msi;
uint err;
if (0 != (err = NativeMethods.MsiOpenPackageW(args[0],out msi)))
{
Console.Error.WriteLine(\"Can\'t open MSI,error {0}\",err);
return 1;
}
// Strings available in all MSIs
string productCode;
using (msi)
{
if (0 != NativeMethods.MsiGetProductProperty(msi,\"ProductCode\",out productCode))
throw new InvalidOperationException(\"Can\'t obtain product code\");
Console.WriteLine(productCode);
return 0;
}
}
}
Subversion上的完整示例,网址为http://ankhsvn.open.collab.net/svn/ankhsvn/trunk/src/tools/Ankh.Chocolatey/
使用用户名\'guest \',不输入密码。
, private static bool GetUninstallString(string ProductName)
{
try
{
RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine,RegistryView.Registry64);
var key = localKey.OpenSubKey(@\"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\") ??
localKey.OpenSubKey(
@\"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\");
if (key == null)
return false;
return key.GetSubKeyNames()
.Select(keyName => key.OpenSubKey(keyName))
.Select(subkey => subkey.GetValue(\"DisplayName\") as string)
.Any(displayName => displayName != null && displayName.Contains(ProductName));
}
catch
{
// Log message
return false;
}
}
这对于按产品名称搜索字符串非常有用