私はC#でアプリケーションを作成しているところです。このアプリケーションは、相互運用機能を介してExcelスプレッドシート(現在は2007年)を開き、魔法をかけてから閉じます。「魔法」の部分は重要であるため、このアプリケーションには、Excelによって生成された多くのCOMオブジェクトへの多くの参照が含まれます。
私は以前にこの種のアプリケーションを作成しましたが(実際には何度も)、COMオブジェクトと対話するための快適で「良い匂い」のアプローチを見つけたことがありません。問題の一部は、重要な調査にもかかわらず、COMを完全に理解していないことと、相互運用ラッパーがおそらく非表示にすべきではない多くの情報を非表示にしていることです。コミュニティからの非常に多くの異なる、矛盾する提案があるという事実は、事態をさらに悪化させるだけです。
タイトルからわからない場合は、調査を行いました。タイトルはこの投稿をほのめかしています:
Excel相互運用オブジェクトを適切にクリーンアップするにはどうすればよいですか?
2008年に最初に尋ねられたアドバイスは、当時は非常に役に立ち、堅実でした(特に、「comオブジェクトで2つのドットを使用しない」ビット)が、現在は時代遅れのようです。2010年3月、Visual Studioチームは、 Marshal.ReleaseComObjectが危険であると見なされていることを仲間のプログラマーに警告するブログ記事を投稿しました。この記事では、cbrummeのWebLog> ReleaseComObjectとインターフェイスポインターとランタイム呼び出し可能ラッパー(RCW)の間のマッピングという、2つの記事を参照しました。これは、人々がずっとReleaseComInteropを誤って使用していることを示唆しています(cbrumme:「適度な数のマネージコードで自由に渡されるCOMオブジェクト。ReleaseComObjectは使用しないでください」)。
メモリリーク(アプリケーションが閉じた後もExcelはバックグラウンドで実行を継続します)とInvalidComObjectExceptionsの間を正常にナビゲートできる、適度に複雑なアプリケーション、できれば複数のスレッドを使用するアプリケーションの例はありますか?COMオブジェクトを作成されたコンテキストの外で使用できるが、アプリケーションが終了した後でもクリーンアップできるものを探しています。これは、管理対象に効果的にまたがることができるメモリ管理戦略のハイブリッドです。 /アンマネージドディバイド。
この問題への正しいアプローチについて説明している記事またはチュートリアルへの参照は、非常に高く評価されている代替手段です。私の最善のGoogle-fuの努力は、明らかに間違ったReleaseComInteropアプローチを返しました。
更新:(
これは答えではありません)
投稿して間もなくこの記事を発見しました:
JakeGinnivanによるVSTOとCOMの相互運用
私は、拡張メソッドを介してCOMオブジェクトを「AutoCleanup」クラスにラップするという彼の戦略を実装することができました。その結果にはかなり満足しています。COMオブジェクトが作成されたコンテキストの境界を越え、ReleaseComObject関数を使用できるようにするソリューションは提供されていませんが、少なくとも、きちんとした読みやすいソリューションを提供しています。
これが私の実装です:
class AutoCleanup<T> : IDisposable {
public T Resource {
get;
private set;
}
public AutoCleanup( T resource ) {
this.Resource = resource;
}
~AutoCleanup() {
this.Dispose();
}
private bool _disposed = false;
public void Dispose() {
if ( !_disposed ) {
_disposed = true;
if ( this.Resource != null &&
Marshal.IsComObject( this.Resource ) ) {
Marshal.FinalReleaseComObject( this.Resource );
} else if ( this.Resource is IDisposable ) {
( (IDisposable) this.Resource ).Dispose();
}
this.Resource = null;
}
}
}
static class ExtensionMethods {
public static AutoCleanup<T> WithComCleanup<T>( this T target ) {
return new AutoCleanup<T>( target );
}
}