11

我想在桌面应用程序中读取 C# 中 MSI 的属性。我正在使用以下代码:

    public static string GetMSIProperty( string msiFile, string msiProperty)
    {
        string retVal= string.Empty ;

        Type classType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
        Object installerObj = Activator.CreateInstance(classType);
        WindowsInstaller.Installer installer = installerObj as WindowsInstaller.Installer;

        Database database = installer.OpenDatabase("C:\\DataP\\sqlncli.msi",0 );   

        string sql = String.Format("SELECT Value FROM Property WHERE Property=’{0}’", msiProperty);

        View view = database.OpenView(sql);

        Record record = view.Fetch();

        if (record != null)
        {
            retVal = record.get_StringData(1);
        }
        else
            retVal = "Property Not Found";

        return retVal;            
    }

但是我收到错误,因为 System.Runtime.InteropServices.COMException 未处理。

sqlncli.msi 文件物理上放置在 c:\DataP 位置。在调试时我发现数据库不包含 installer.OpenDatabase() 语句之后的数据。

请建议我如何解决此问题并在 c# 中获取 MSI 属性。

提前致谢。

4

5 回答 5

18

Windows Installer XML 的部署工具基础 (WiX DTF) 是 Microsoft 的一个开源项目,其中包括 Microsoft.Deployment.WindowsInstaller MSI 互操作库。使用它来执行这些类型的查询要容易得多和可靠得多。它甚至有一个 LINQ to MSI 提供程序,允许您将 MSI 表视为实体并针对它们编写查询。

using System;
using System.Linq;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Deployment.WindowsInstaller.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using(var database = new QDatabase(@"C:\tfs\iswix.msi", DatabaseOpenMode.ReadOnly))
            {
                var properties = from p in database.Properties
                                 select p;

                foreach (var property in properties)
                {
                    Console.WriteLine("{0} = {1}", property.Property, property.Value);
                }
            }

            using (var database = new Database(@"C:\tfs\iswix.msi", DatabaseOpenMode.ReadOnly))
            {
                using(var view = database.OpenView(database.Tables["Property"].SqlSelectString))
                {
                    view.Execute();
                    foreach (var rec in view) using (rec)
                    {
                        Console.WriteLine("{0} = {1}", rec.GetString("Property"), rec.GetString("Value"));
                    }
                }
            }

            Console.Read();
        }
    }
}
于 2012-12-20T18:41:14.003 回答
2

我是通过以下方式做到的:

String inputFile = @"C:\\Rohan\\sqlncli.msi";

// Get the type of the Windows Installer object
Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");

// Create the Windows Installer object
WindowsInstaller.Installer installer = (WindowsInstaller.Installer)Activator.CreateInstance(installerType);

// Open the MSI database in the input file
Database database = installer.OpenDatabase(inputFile, 0);

// Open a view on the Property table for the version property
View view = database.OpenView("SELECT * FROM _Tables");

// Execute the view query
view.Execute(null);

// Get the record from the view
Record record = view.Fetch();

while (record != null)
{
    Console.WriteLine(record.get_StringData(0) + '=' + record.get_StringData(1) + '=' + record.get_StringData(2) + '=' + record.get_StringData(3));
    record = view.Fetch();
}

它为我工作。

于 2012-12-20T09:33:12.357 回答
1

SQL 字符串不正确。它应该是:

SELECT `Value` FROM `Property` WHERE `Property`.`Property` = ’{0}’
于 2012-12-20T07:04:20.063 回答
1

我试图重用这段代码,我必须做的唯一改变是让 Devashri 发布的代码工作是这一行:

string sql = String.Format("SELECT `Value` FROM `Property` WHERE `Property`='{0}'", msiProperty);

注意单引号!

于 2013-10-20T06:16:10.800 回答
-1

截至 2020 年 4 月,它将是

Type installerType { get; set; }
WindowsInstaller.Installer installerObj { get; set; }
...
installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer"); 
installerObj = (WindowsInstaller.Installer)Activator.CreateInstance(installerType);
var installer = installerObj as WindowsInstaller.Installer;
...
private void lnkSelectMsi_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
   WindowsInstaller.Database msiDatabase = installerObj.OpenDatabase(txtMsiPath.Text, 0);
   readMsiTableColumn(msiDatabase, cmbTable.Text, cmbColumn.Text);
}

   private void readMsiTableColumn(WindowsInstaller.Database msiDatabase, string table)
    {
        WindowsInstaller.View msiView = null;
        Record record = null;
        string s = string.Empty;
        try
        {
            msiView = msiDatabase.OpenView($"Select * from _Columns");
            msiView.Execute();
            record = msiView.Fetch();
            int k = 0;
            while (record != null)
            {
                if (record.StringData[1].Equals(table, StringComparison.OrdinalIgnoreCase))
                {
                    k++;
                    s += $"{record.StringData[3],-50} ";
                }
                record = msiView.Fetch();
            }
            s += nl;
            s += "".PadRight(50 * k, '-') + nl;
            msiView.Close();

            msiView = msiDatabase.OpenView($"Select * from {table}"); 
            msiView.Execute();
            record = msiView.Fetch();

            while (record != null)
            {
                string recordValue = string.Empty;
                for (int i = 1; i < record.FieldCount + 1; i++)
                {
                    try { recordValue += $"{record.StringData[i],-50} "; }
                    catch (Exception ex) { recordValue += $"{i}. err {ex.Message}; "; }
                }
                s += recordValue + nl;
                record = msiView.Fetch();
            }
            msiView.Close();
            txtRes.Text = s;
        }
        catch (Exception ex) { txtRes.Text = ex.Message; }
    }
于 2020-04-27T22:15:39.940 回答