タイトル : Re: SeriesCollection.Add後、Excelのタスクが残る 投稿日 : 2020/01/27(Mon) 15:03 投稿者 : 魔界の仮面弁士
> '確実なオブジェクト解放用 > ''' Excelオブジェクトの完全な開放 解放(Release)と開放(Open,Free)になっていますよ。 > タスクマネージャーで見るとExcelのタスク「Microsoft Excel」が残ってしまいます。 まずは解放時に、ReleaseComObject の戻り値が 0 になっていることを確認してみてください。 ReleaseComObject は、呼び出すたびに COM の参照カウントを -1 するようになっており、 参照カウントが 0 になったときに、COM オブジェクトが処分されます。 全ての解放処理で ReleaseComObject が 0 を返してくるにも関わらず、 それでも Excel が残ってしまうようであれば、ReleaseComObject に渡し忘れている COM オブジェクトが残っている、ということを意味します。 一方、ReleaseComObject の戻り値が 1 以上になっている場合、それは 同じ COM オブジェクトへの複数の参照が生成された状態を意味します。 通常、このメソッドが 0 以外を返す状態になることは少ないのですが、 メソッドをレイトバインドで呼び出したときに、そのメソッド引数に対して COM オブジェクトを Object 型の変数を通じて受け渡した場合、データ型判定時に 内部的な参照カウントが予期せず増大してしまうことがあり、その場合、 ReleaseComObject を 1 回呼び出しただけでは解放されないことがあります。 もしも 0 を返してこなかった場合には、ReleaseComObject の代わりに FinalReleaseComObject を呼び出せば、そのオブジェクトの参照カウントが一気に 0 になります。 > Do Until SeriesCollectionObj.Count = 0 > ObjRelease(srsObj) '使い回しは解放が必要。 > srsObj = SeriesCollectionObj(1) 'コレクションは代入して消去が必要。 > srsObj.Delete() > Loop 順番的には Do Until SeriesCollectionObj.Count = 0 srsObj = SeriesCollectionObj(1) srsObj.Delete() ObjRelease(srsObj) Loop とするべきでは無いでしょうか? 元のコードだと、最後に取得した srsObj の中身を解放することなく、 ループ後の @ に到達してしまい、同じ変数に対して別のインスタンスへの参照が セットされてしまい、その前に保持されていたオブジェクトの解放処理が漏れることになりそうです。 === 以下蛇足 === > Option Strict Off > Option Explicit On > > Dim rngObj As Range = Nothing > > ObjRelease(rngObj) > > Sub ObjRelease(ByRef obj As Object) 上記では、仮引数が As Object 、実引数が As Range となっており、 それぞれ異なるデータ型が受け渡されていることになります。 現状の「Option Strict Off」であればコンパイルは通るのですが、 その場合、メソッドの呼び出し時において ObjRelease(wbkObj) という処理が Dim dummy As Object = wbkObj ObjRelease(dummy) wbkObj = DirectCast(dummy, Workbook) という処理に置き換えられることになるため、無駄なやりとりが多くなります。 そこで、このようなケースでは Sub ObjRelease(ByRef obj As Object) ではなく、 Sub ObjRelease(Of T)(ByRef obj As T) というメソッド定義に変更することをお奨めします。この方が実行効率が良いですし、 「Option Strict On」時にもそのまま使うことができます。 ちなみに、「If Not (obj Is Nothing) Then」というのは古い書き方なので、現在は 英文法的に「If obj IsNot Nothing Then」の方がスマートかと思います。 |