如何在C#中将WindowsInstaller.Record转换为System.Data.Dataset或数据表(读取M

本文关键字:Dataset Data 数据表 读取 System 中将 WindowsInstaller 转换 Record | 更新日期: 2023-09-27 17:49:35

我想读取MSI文件(Windows安装程序包(。我编写了一个函数,如下所示,它接受两个输入参数:msifileName和TableName,并返回一个数据表,该数据表是MSI表之一。

public DataTable ReadMsiPropertyTable(string msiFile, string tableName)
    {            
        Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
        WindowsInstaller.Installer installer = (WindowsInstaller.Installer)Activator.CreateInstance(installerType);
        Database database = installer.OpenDatabase(msiFile, 0);
        string sqlQuery = String.Format("SELECT * FROM {0}",tableName);
        View view = database.OpenView(sqlQuery);
        view.Execute(null);
        Record record = view.Fetch();
        DataTable msiPropertyTable = new DataTable();
        msiPropertyTable.Columns.Add("Column1", typeof(string));
        msiPropertyTable.Columns.Add("Column2", typeof(string));
        msiPropertyTable.Columns.Add("Column3", typeof(string));
        msiPropertyTable.Columns.Add("Column4", typeof(string));
        while (record != null)
        {
            int fieldCount;
            fieldCount = record.FieldCount;
            msiPropertyTable.Rows.Add(record.get_StringData(0), record.get_StringData(1), record.get_StringData(2), record.get_StringData(3));                
            record = view.Fetch();
        }
        return msiPropertyTable;
    }

使用上面的代码片段,Record的行数和列数是未知的。所以我静态地只返回四列。我想返回记录中MSI表的所有行和列。

所以请告诉我如何将视图或记录的输出转换为数据集,然后绑定到Datatable。或者还有其他方法可以返回所有的行和列吗。提前谢谢。

如何在C#中将WindowsInstaller.Record转换为System.Data.Dataset或数据表(读取M

下面是使用互操作类型而不是DTF类型的类似逻辑。正如你所看到的,这是更多的工作。由于涉及COM而不是P/Invoke,因此它也更加脆弱。此外,如果您可以消除创建ADO.NET数据表的要求,DTF支持LINQ查询和数据绑定。换句话说,我写这篇文章只是为了好玩。我永远不会在实际代码中使用这个方法。

 public static DataTable ReadMsiPropertyTable(string msiFile, string tableName)
        {
            DataTable dataTable = new DataTable(tableName);
            Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
            Installer installer = (WindowsInstaller.Installer)Activator.CreateInstance(installerType);
            Database database = installer.OpenDatabase(msiFile, MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly);
            string sqlQuery = String.Format("SELECT * FROM {0}", tableName);
            View view = database.OpenView(sqlQuery);
            view.Execute(null);
            Record names = view.ColumnInfo[MsiColumnInfo.msiColumnInfoNames];
            Record types = view.ColumnInfo[MsiColumnInfo.msiColumnInfoTypes];
            Record row = view.Fetch();
            for (int index = 1; index < names.FieldCount+1; index++)
            {
                string columnName = names.get_StringData(index);
                string columnSpec = types.get_StringData(index);
                switch (columnSpec.Substring(0, 1).ToLower())
                {
                    case "s":
                        dataTable.Columns.Add(columnName, typeof(String));
                        break;
                    case "l":
                        dataTable.Columns.Add(columnName, typeof(String));
                        break;
                    case "i":
                        dataTable.Columns.Add(columnName, typeof(Int32));
                        break;
                    case "v":
                        dataTable.Columns.Add(columnName, typeof (Stream));
                        break;
                }
            }
            while (row != null)
            {
                DataRow dataRow = dataTable.NewRow();
                for (int index = 0; index < dataTable.Columns.Count; index++)
                {
                    if(dataTable.Columns[index].DataType == typeof(String))
                    {
                        dataRow[index] = row.StringData[index + 1];
                    }
                    else if(dataTable.Columns[index].DataType == typeof(Int32))
                    {
                        dataRow[index] = row.IntegerData[index + 1];
                    }
                    else if(dataTable.Columns[index].DataType == typeof(Stream))
                    {
                       // Insanity has it's limits. Not implemented.
                    }
                }
                dataTable.Rows.Add(dataRow);
                row = view.Fetch();
            }
            return dataTable;
        }

我建议您使用部署工具基础(使用MSI包的API库,与WiX工具集一起使用(来完成此任务。API既方便又直观。

例如,有一个类Database。您可以通过向构造函数提供MSI包的路径来创建它:

var db = new Database("path'to'MSI");

它提供了有关MSI数据库的任何信息。例如,db.Tables["TableName"]返回TableInfo类的一个实例,该实例依次包含有关列、行、主键等的信息。

下载并安装WiX工具集,并从DTF.chm帮助文件中获取更多信息。

以下是如何使用DTF为数据库、视图和记录对象创建类型。使用COM Interop会很类似,但我不想用困难的方式做事。

public static DataTable TableToDataTable( string msiPath, string tableName )
{
    DataTable dataTable = null;
    using(var database = new Database(msiPath, DatabaseOpenMode.ReadOnly))
    {
        using(var view = database.OpenView("SELECT * FROM `{0}`", tableName))
        {
            view.Execute();
            dataTable = new DataTable(tableName);
            foreach (var column in view.Columns)
            {
                dataTable.Columns.Add(column.Name, column.Type);
            }
            foreach (var record in view) using (record)
            {
                var row = dataTable.NewRow();
                foreach (var column in view.Columns)
                {
                    row[column.Name] = record[column.Name];
                }
                dataTable.Rows.Add(row);
            }
        }
    }
    return dataTable;
}
相关文章: