- - PR -
Vb.netでExcelが終了しない
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2004-08-18 08:54
ひどりさんの、
太字にしたところが、とっても重要なように思います また、ある環境ではOkでも、別の環境ではNGなら、NGな環境をOkにする作りにしておく必要がある、と思います。 | ||||||||
|
投稿日時: 2004-08-19 02:54
GC.Collect() の方がキーになっていると先に書いたんですが,
理由は,GC.Collect() で RCW 自体が開放されて, 握っていたCOMオブジェクトを放すためのようです。 .NET Client --> RCW --> COMサーバー ↑ ここの参照は,1止まりなので RCWがGCされると, .NET Client からの参照数にかかわらず 自動的にIUnknown::Releaseするため ということで,GC.Collectは,最終手段としてかなり有効なため GC.Collectしてもインスタンスが残っている場合は, まず,暗黙の既定のインスタンスができている可能性が高いです。 >----------------------------------------------------------- また,よく調べてみると, ReleaseCOMObjectは, GC.Collect() を呼ぶ必要がないように用意されたということなので, .ReleaseCOMObject(...) をしつこく呼でいても, GC.Collect() を最後に呼んでしまうのならば, 苦労した意味がなくなってしまうような気がします。 GC.Collect() を最後に呼ぶのならば, あまり細かいことを気にしなくて ただ,GC.Collect() すればいいことになるわけで。 >------------------------------------------------------- で,ReleaseCOMObject は, GC.Collectに頼らなくてもいいように用意されたメソッドなのに, なので,ReleaseCOMObject(...) を小刻みに呼んでいるのに どうして開放されないのか,再度,調べてみると... まず,Cells を Range でうけて,開放します。 >------------------------------------------------------------ 略 Dim wsh As Excel.Worksheet Dim rng As Excel.Range 略 rng = wsh.Cells For i As Integer = 1 To 100 rng(i, 1).Formula = "Hoge" & CStr(i) Next System.Runtime.InteropServices.Marshal.ReleaseComObject(rng) rng = Nothing 略 >------------------------------------------------------------------ 上のパターンだとまだ残ります。 で, Excelのオブジェクトをオブジェクトブラウザで眺めていたんですが, rng(i, 1) ですが,よく考えてみると,.Cells( row , col ) は, Rangeオブジェクトから, 再度,新規のRangeオブジェクトが返ってくる形のようです。 なので, >------------------------------------------------------------------ 略 Dim wsh As Excel.Worksheet Dim rng As Excel.Range 略 rng = wsh.Cells For i As Integer = 1 To 100 Dim tmpRange As Excel.Range tmpRange = rng(i, 1) tmpRange.Formula = "Hoge" & CStr(i) System.Runtime.InteropServices.Marshal.ReleaseComObject(tmpRange) tmpRange = Nothing Next System.Runtime.InteropServices.Marshal.ReleaseComObject(rng) rng = Nothing 略 >--------------------------------------------------------------------- のようにしたらみごと, GC.Collect() を呼ばないでも ReleaseCOMOjbectだけで,インスタンスはきれいに消えました。 なので, worksheet.Cells( row , col ).Format = "Hoge" は, rng1 = worksheet.Cells rng2 = rng1( row , col ) rng2.Format = "Hoge" のように分割しないといけないということのようです。 つまり,一度rangeでうけていても, あるセルを参照するたびに,rangeでうけて, そして,それを毎回 ReleaseCOMObject( range ) する必要があるということのようです。 ReleaseCOMObjectだけで,消えてくれたので,うれしいのですが, 死ぬほど面倒なので,GC.Collect() が許される状況ならば, VB/VBA上のコードのように,今までどおり,obj = Nothing するだけにしておいて, 最後に GC.Collect() でまるっとRCWを開放した方が やっぱり楽かなという感じです... [ メッセージ編集済み 編集者: 稍丼 編集日時 2004-08-19 03:26 ] [ メッセージ編集済み 編集者: 稍丼 編集日時 2004-08-19 03:27 ] [ メッセージ編集済み 編集者: 稍丼 編集日時 2004-08-19 03:28 ] [ メッセージ編集済み 編集者: 稍丼 編集日時 2004-08-19 03:29 ] | ||||||||
|
投稿日時: 2004-08-19 09:01
稍丼さん
詳細にありがとうございます。 先にリンクをしています、AI-Lightの投稿では、『GC.Collect()をしてもダメだった』とあります。この方の最初の投稿で、.NET側のプログラムで保持している変数は、すべてNothing代入をしているので、参照が残っているという状況ではない、と思います。 自分がやってみた感想としては、GC.Collect()をすることは絶対で、ReleaseCOMObjectを併用しておく方が安全、ってところでしょうか。ExcelApplicationなどは、CloseしてQuitしてReleaseしておかなければ落ちてくれないように、記憶しています。 | ||||||||
|
投稿日時: 2004-08-19 18:05
> 自分がやってみた感想としては、GC.Collect()をすることは絶対で、
> ReleaseCOMObjectを併用しておく方が安全、ってところでしょうか。 COM Interop( 特に,RCW(Runtime Callable Wrapper)) の実装?が 当てにならない(flawed)という記述を,ひどりさんのレスだけでなく, 調べてみると,海外のMVPの方のブログでも見かけました。 なので,今のところは, 安全な方へ転ぶように書くのが無難なんでしょうね... |