How to read MSI properties in c#

2019-02-09 08:48发布

问题:

I want to read properties of MSI in C# in desktop application.I am using following code:

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

But I am getting error as System.Runtime.InteropServices.COMException was unhandled.

the sqlncli.msi file is physically placed at c:\DataP location. While debugging I found that database does not contain the data after installer.OpenDatabase() statement.

Please suggest me how to resolve this issue and get MSI properties in c#.

Thanks in advance.

回答1:

Windows Installer XML's Deployment Tools Foundation (WiX DTF) is an Open Source project from Microsoft which includes the Microsoft.Deployment.WindowsInstaller MSI interop library. It's far easier and more reliable to use this to do these sorts of queries. It even has a LINQ to MSI provider that allows you to treat MSI tables as entities and write queries against them.

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();
        }
    }
}


回答2:

The SQL string is incorrect. It should be:

SELECT `Value` FROM `Property` WHERE `Property`.`Property` = ’{0}’


回答3:

I was trying to re-use this code, and the only change I had to make to get the code posted by Devashri to work is this line:

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

Watch out for the single quotes!



回答4:

I did it in following way:

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();
}

And its working for me.