1

MSI ファイルを閉じるのに助けが必要です。

MSI ファイルを開いて更新できる MSI ファイル エディターを作成しています。しかし、問題は、同じファイルを再度開いてみると (更新された msi をクロスチェックするためだけに)、エラーがスローされることです。

OpenDatabase,DatabasePath,OpenMode

この行で

database = installer.OpenDatabase(msiFile.FullName, MsiOpenDatabaseMode.msiOpenDatabaseModeTransact);

だから、msiファイルがすでに開いているからだと思います。すでに開いている msi を閉じるのを手伝ってくれる人はいますか。

4

4 に答える 4

3

WindowsInstaller.Installer COM オブジェクトから生成された相互運用ライブラリを使用していると思います。あなたはそれをしたくありません。これで私を信頼してください。代わりに、Windows インストーラー XML をダウンロードし、SDK フォルダーにある Microsoft.Deployment.WindodsInstaller アセンブリを探します。このライブラリは Deployment Tools Foundation (DTF) の一部であり、Windows インストーラと相互運用するためのゴールド スタンダードです。

DTF では、Database クラスが IDisposable インターフェイスを実装するため、最も洗練された方法は、using ステートメント内に配置することです。

using(Database database = new Database(...))
{
 // Do Stuff Here
}

ブロックが完了すると、.NET は Dispose() メソッドを自動的に呼び出します。これにより、データベースが閉じられ、アンマネージ ハンドルが解放されます。ガベージ コレクターは、その後の重要でない時点でマネージ クラスをクリーンアップするように通知されます。Dispose の呼び出しに失敗した場合 (暗黙的または明示的に)、管理されていないリソースは、ガベージ コレクターがクリーンアップするまで解放されません。これは、ご覧のとおり良いことではありません。

于 2013-02-11T13:47:07.637 に答える
2

ねえスティーブンとクリストファー、これが私があなたの貴重な提案を使って私の問題を解決した方法です.

アプリケーション全体でさまざまなトランザクションにデータベースが必要なため、データベースをグローバル変数として使用しているため、msi ファイルを開く前にこれらの行を追加しました。

if (view != null)
   {
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(view);
      view = null;
   }
if (database != null)
   {
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(database);
      database = null;
   }
GC.Collect();

私の答えが、同じシナリオで立ち往生している人々にも役立つことを願っています。

于 2013-02-12T07:35:28.950 に答える
1

データベースを変数にnullに設定するか、変数を強制的に範囲外にします。これにより、開いているハンドルが解放されます。

または、ガベージ コレクターを強制的に実行してハンドルを放棄する必要がある場合もあります。C# でガベージ コレクションを強制するためのベスト プラクティス

于 2013-02-11T13:08:27.680 に答える
0

すべてのハンドルを解放する必要があります。次に例を示します。

Database database = _installer.OpenDatabase(...);
View view = database.OpenView(query);
view.Execute();
Record record = view.Fetch();

Marshal.FinalReleaseComObject(record);
view.Close();
Marshal.FinalReleaseComObject(record);
Marshal.FinalReleaseComObject(database);
record = null;
view = null;
database = null;
GC.Collect();

試してみてください...最終的にはうまくいくはずです。

于 2013-06-25T16:30:18.100 に答える