経緯
COM Objectといえば「ReleaseComObject
で解放だー」みたいな印象があるが、.NETからExcelとか操作してると、いろんなオブジェクトが参照カウント増やしてくれやがるので、管理できなくなるしtry{...}finally{解放処理}
のネストがエグくなる。
そんななか
[Marshal.ReleaseComObject
は危険な場合がある]
(https://www.infoq.com/jp/news/2010/03/ReleaseComObject-Dangerous/)
というのを目にして、どうやればよいのか、
COMオブジェクト×.NETに関するKindle書籍(下記「参考書籍」参照)を持ってたので少し調べてみた。
参考書籍
.NET and COM: The Complete Interoperability Guide - Adam Nathan著
著者はMicrosoftの中の人のよう。
読破できる気がしないので、書籍内検索する形で活用。
GCに任せる方法
6章Advanced Topics for Using COM Components の Listing 6.5 とその前のあたりの記載より。
GCに任せるという手法が紹介されている。(推奨なのかどうかは読解できず。)
(まんま載せると著作権的によくなさそうなので雰囲気だけ。)
using System.Runtime.CompilerServices;
[MethodImpl(MethodImplOptions.NoInlining)]
static void WorkWithMsOfficeComponent()
{
XXX(Excelとか).Application app = new XXX.Application();
...
app.Quit();
}
static void Main()
{
WorkWithMsOfficeComponent();
GC.Collect();
GC.WaitForPendingFinalizers();
}
スコープ(変数の生存区間)の短いauto変数に押し込めることができるなら、上記のやりかたが楽っぽい。
属性 [MethodImpl(MethodImplOptions.NoInlining)]
を指定しているのは、JIT1によるインライン展開を防止してGCを意図通りに機能させるため。
参考サイト
計測方法とかが参考になりそう。(時間なくてまだ試せていないです。)
.NETを使ったOfficeの自動化が面倒なはずがない―そう考えていた時期が俺にもありました。
-
JIT(Just in time)コンパイラ(実行時にNativeな実行プログラムにコンパイルされる)によってインライン展開されると、変数の生存区間がプログラマの意図通りにならず、結果としてGCがプログラマの意図通りに動作しない。 ↩