2011-06-14 171 views
6

我有一个C#程序,我必须获取安装的msi的产品代码。我只有msi名称作为输入。这可以通过编程来完成吗?获取产品安装的Msi代码

+0

你使用注册表编辑器来搜索注册表的机器上安装的软件非常有用? – 2011-06-14 14:46:05

+0

有关完整源代码的最终解决方案吗? – Kiquenet 2012-07-27 06:40:21

+0

** [DTF(部署工具基础)](https://serverfault.com/questions/577969/is-it-possible-to-disable-msiexec-help-gui/596519#596519)**是一堆随WiX下载提供的.NET类将为您提供一种访问和修改MSI文件的简单方法,而无需任何COM互操作或阻塞。有关更多上下文,请参阅提供的链接中的信息。 ** [下载WiX](http://wixtoolset.org/)**以获取DTF组件。 – 2017-07-31 00:22:15

回答

4

这是我曾经得到任何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内子。我希望这可能是产品代码。

+2

如果您在64位计算机上使用此代码并且您的应用程序是32位,这将失败,因为它会将您重定向到软件中的“Wow6432Node”。改为使用'RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,RegistryView.Registry64).OpenSubKey(path)'。 – modiX 2016-08-04 09:07:17

6

this question有帮助吗?他们想要获得产品名称,但也可能适用于产品代码?

编辑
如果没有MSI文件本身来访问数据库(通过上面的链接到的其他问题的建议),您可以尝试搜索以下注册表路径为您的MSI的名字文件:

HKEY_CLASSES_ROOT\Installer\Products\*\SourceList 

Products分支下有很多条目。他们每个人都是产品的关键。每个分支应包含SourceList节点,该节点又应包含值PackageName。该值包含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 
    } 
} 
+0

好的:-1因为...? – 2011-06-14 14:46:51

+0

但是,密钥名称实际上是产品代码的混乱版本。请参阅此处以获取从ProductCode到注册表项格式的帮助(http://stackoverflow.com/questions/1881643/msi-product-code-from-product-id/1881818#1881818)。你只需要反转即可解密密钥名称。 – 2014-07-05 15:17:47

1

该代码直接从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, CharSet = CharSet.Unicode, 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, string szProperty, 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; 
     } 
    } 
} 
在颠覆

全部例如在http://ankhsvn.open.collab.net/svn/ankhsvn/trunk/src/tools/Ankh.Chocolatey/ 使用用户名 '客户',没有密码。

2

有最快捷最简单的方法 - 使用带有条件查询字符串的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; 
    } 
+1

这个程序不错,它消耗了很多时间 – 2015-10-08 04:00:58

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

这是搜索字符串由产品名称

相关问题