1

MSIファイル(Windows Installer Package)を読み込みたい。msifileName と Table Name の 2 つの入力パラメータを取り、MSI テーブルの 1 つであるデータ テーブルを返す関数を以下のように作成しました。

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 の行数と列数は不明です。SO 私は静的に 4 つの列のみを返しています。レコードにある MSI テーブルのすべての行と列を返したいです。

ビューまたはレコードの出力をデータセットに変換してからデータテーブルにバインドする方法を教えてください。または、すべての行と列を返す他の方法はありますか。前もって感謝します。

4

3 に答える 3

3

このタスクには、Deployment Tools Foundation (MSI パッケージで動作する API ライブラリであり、WiX ツールセットに付属しています) を使用することをお勧めします。API は便利で簡単です。

たとえば、クラスがありDatabaseます。MSI パッケージへのパスをコンストラクターに指定することで作成できます。

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

また、MSI データベースに関する情報を提供します。たとえばdb.Tables["TableName"]、クラスのインスタンスを返します。このインスタンスにはTableInfo、列、行、主キーなどに関する情報が含まれています。

WiX Toolsetをダウンロードしてインストールし、DTF.chmヘルプ ファイルから詳細情報を取得します。

于 2012-12-24T15:22:03.310 に答える
3

DTF 型ではなく相互運用型を使用した同様のロジックを次に示します。ご覧のとおり、より多くの作業が必要です。また、P/Invoke の代わりに COM が関与するため、脆弱性も大きくなります。また、ADO.NET DataTable を作成する必要をなくすことができれば、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;
        }
于 2012-12-26T22:13:07.970 に答える
2

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;
}
于 2012-12-26T20:32:49.893 に答える