RCWはファイナライズで自動的にReleaseするっぽい。検証してみた。
正攻法で考えると、ReleaseComObject を必ず行う。なのだけど。。。
マネージ コードから COM コンポーネントを使用する場合、tlbimp.exe を使用 していわゆるランタイム呼び出し可能ラッパー (RCW) を生成します。RCW によっ て COM コンポーネントの機能がマネージ環境に公開されます。なお、tlbimp.exe は、Visual Studio® で COM コンポーネントを参照するとバックグラウンドで実行 されます。RCW はデバッガで System.__ComObject と表示されるので、簡単に識別 できます。RCW は、COM オブジェクトへのアンマネージ ポインタを 1 つ保持し、 オブジェクトで AddRef および Release を呼び出す .NET 型です。AddRef はコン ポーネントが作成されると呼び出され、Release は RCW がファイナライズされると 呼び出されます。
という記事をみつけた。
「ReleaseはRCWがファイナライズされると呼び出されます。」と書かれてる。
これはつまり、
ReleaseComObject を全く行わずとも、GCでファイナライズを強制実行させればCOMも解放できるということか?
試してみる。
流れとしては、
フォームの上のボタンを押すとExcel呼び出してセルに書いたりする。
最後にファイナライズを強制実行する。
using System.Runtime.InteropServices; : private void button1_Click(object sender, System.EventArgs e) { this.excel_ctrl(); // 以下を、excel_ctrl の中に入れてしまうと、Excelプロセスが残るのでここに配置してみた。 System.GC.Collect(); // アクセス不可能なオブジェクトを除去 System.GC.WaitForPendingFinalizers(); // ファイナライゼーションが終わるまでスレッド待機 System.GC.Collect(); // ファイナライズされたばかりのオブジェクトに関連するメモリを開放 } private void excel_ctrl() { Excel.Application excel = new Excel.Application(); excel.Visible = true; excel.Workbooks.Add(Type.Missing); Excel.Worksheet worksheet = (Excel.Worksheet)excel.ActiveSheet; ((Excel.Range)worksheet.get_Range("C6", Type.Missing)).Value2 = "Hello"; ((Excel.Range)worksheet.get_Range("C6", Type.Missing)).Interior.ColorIndex = 6; ((Excel.Worksheet)excel.ActiveSheet).get_Range("C7", Type.Missing).Value = "xxx"; ((Excel.Worksheet)excel.ActiveSheet).get_Range("C7", Type.Missing).Borders.ColorIndex = 7; ((Excel.Worksheet)excel.ActiveSheet).Copy(excel.ActiveSheet, Type.Missing); excel.Quit(); }
Excelプロセス残らない。
ちょっと驚いた。
ただし、Finalizeでのリソース解放は最終手段であるし、実際
Object.Finalize メソッド (System)
によると、
- ガベージ コレクション実行中のファイナライザの実行時期は未定義です。
- 2 つのオブジェクトのファイナライザが特定の順序で実行されることは保証されません。
とあるので、これに頼ってしまってよいのか疑問は残るんだけどね。