C# 获取产品代码为的已安装Windows Installer软件包的证书

C# 获取产品代码为的已安装Windows Installer软件包的证书,c#,windows-installer,certificate,pinvoke,C#,Windows Installer,Certificate,Pinvoke,我有几个产品代码从MsiEnumProducts中筛选出来,需要获得分配给它们的证书。 使用MsiOpenDatabase应该可以获得证书,但我不知道如何可靠地获得.msi文件的路径 我希望避免使用外部程序集(如wix),而只使用pinvoke。给定产品代码,调用传递属性名称INSTALLPROPERTY\u LOCALPACKAGE将返回缓存的安装程序包在C:\Windows\installer中的位置 拥有缓存包后,调用可以检索证书 使用pInvoke的示例: using System; u

我有几个产品代码从MsiEnumProducts中筛选出来,需要获得分配给它们的证书。 使用MsiOpenDatabase应该可以获得证书,但我不知道如何可靠地获得.msi文件的路径


我希望避免使用外部程序集(如wix),而只使用pinvoke。

给定产品代码,调用传递属性名称INSTALLPROPERTY\u LOCALPACKAGE将返回缓存的安装程序包在C:\Windows\installer中的位置

拥有缓存包后,调用可以检索证书

使用pInvoke的示例:

using System;
using System.Text;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("msi.dll", CharSet = CharSet.Ansi, SetLastError = false)]
    static extern int MsiEnumProducts(int iProductIndex, StringBuilder lpProductBuf);

    [DllImport("msi.dll", CharSet = CharSet.Ansi, SetLastError = false)]
    static extern int MsiGetProductInfo(string product, string property, [Out] StringBuilder valueBuf, ref Int32 len);

    [DllImport("msi.dll", CharSet = CharSet.Ansi, SetLastError = false)]
    static extern int MsiGetFileSignatureInformation(string fileName, int flags, out IntPtr certContext, IntPtr hashData, ref int hashDataLength);

    [DllImport("Crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    static extern int CertFreeCertificateContext( IntPtr certContext );

    [DllImport("Crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    static extern int CertGetNameString(IntPtr certContext, UInt32 type, UInt32 flags, IntPtr typeParameter, StringBuilder stringValue, UInt32 stringLength );

    static void Main(string[] args)
    {
        int index = 0;
        StringBuilder productCode = new StringBuilder();
        int result = MsiEnumProducts(index, productCode);
        while (result == 0)
        {
            Console.WriteLine("{0}", productCode);

            Int32 length = 1024;
            StringBuilder fileName = new StringBuilder();
            result = MsiGetProductInfo(
                        productCode.ToString(),
                        "LocalPackage",
                        fileName,
                        ref length );
            if (result == 0)
            {
                Console.WriteLine("{0}", fileName);

                IntPtr certContext = IntPtr.Zero;
                IntPtr hashData = IntPtr.Zero;
                int hashDataLength = 0;
                result = MsiGetFileSignatureInformation(
                            fileName.ToString(),
                            0,
                            out certContext,
                            hashData,
                            ref hashDataLength);
                if ( result == 0 )
                {
                    Console.WriteLine("Got Cert");

                    StringBuilder simpleDisplayType = new StringBuilder();
                    int ok = CertGetNameString(
                                certContext,
                                4,                      // == CERT_NAME_SIMPLE_DISPLAY_TYPE
                                0,
                                IntPtr.Zero,
                                simpleDisplayType,
                                1024 );
                    if (ok != 0)
                    {
                        Console.WriteLine("{0}", simpleDisplayType);
                    }

                    CertFreeCertificateContext(certContext);
                }
            }

            ++index;
            result = MsiEnumProducts(index, productCode);
        }
    }
}

我认为MSIAPI中没有任何东西可以做到这一点。大概您已经了解了如何在C:\Windows\Installer中获取缓存MSI的路径。您需要一些其他API来检查应用于此文件的证书。请注意,在Windows 7之前版本上,证书将无效,因为Windows在删除嵌入式CAB时修改了该文件。我相信,如果安装是从原始MSI中提取的文件运行的,则证书也将丢失。我不确定这是否会影响MSIDgitalSignature表及其关联表。只需找到一个签名的MSI文件,运行一个管理员映像并检查表。