いつも参考にさせていただきています。
VisualBasic.NETでExcelファイルを操作するプログラムを作っています。
.NETのCOM連携機能の仕様だからか、マメにMarshal.ReleaseComObject()をしないとExcelのプロセスが残っていまうようなのです。もう少し簡単に書くことはできないでしょうか?
具体的には下記コードで、①だけならプロセスは残らないのですが、続けて②も記述すると、プロセスが残ってしまいます。当然、別変数で扱って、Marshal.ReleaseComObject()すれば大丈夫なんですが、コード量が半端じゃなくなってしまいますので。。。
Dim xlApp As Excel.Application
Dim xlBooks As Excel.Workbooks
Dim xlBook As Excel.Workbook
Dim xlSheets As Object
Dim xlSheet As Excel.Worksheet
Dim xlCells As Object
Dim xlCell As Object
Dim xlVal As Object
xlApp = CreateObject("Excel.Application")
xlBooks = xlApp.Workbooks
xlBook = xlBooks.Open("C:test.xls")
xlSheets = xlBook.Worksheets
xlSheet = xlSheets(1)
xlCells = xlSheet.Cells
①-------------------------
xlCell = xlCells(9, 18)
xlVal = xlCell.Value
xlVal = "2"
---------------------------
②--------------------------
xlCell = xlCells(10, 10)
xlVal = xlCell.Value
xlVal = "3"
----------------------------
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlCell)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlCells)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheets)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook.Worksheets)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBooks)
こんなblogがありました。最後に3通りのアドバイスがあります。
http://blogs.msdn.com/cbrumme/archive/2003/04/16/51355.aspx
Microsoft側でも、.NET Frameworkの今後のバージョンで、この点を
解決できるような仕組みを作れないか検討されているようですが、
少なくとも現在のバージョンでは、自分で解放処理を書く必要があるかと。
> もう少し簡単に書くことはできないでしょうか?
VBから直接制御するかわりに、VBAを埋め込んだ文書を
VB.NETから開くようにする………というのは駄目ですよね。
# もしくは、Visual Studio Tools for Officeを利用するとか。
> コード量が半端じゃなくなってしまいますので
For Eachの処理などは、特に、解放が面倒になったり…。
http://www.divakk.co.jp/aoyagi/csharp_tips_vssenum.html
魔界の仮面弁士さん、ありがとうございます。
ラッパークラスを作成してその中で開放する処理を記述して、
コードの簡素化を図ろうかと考えていますが、
実は、他のオブジェクト指向言語では書いたことがあるのですが、
VB.NETでどうやってラッパークラスを作成して良いのか、
さっぱりわかりません。。。
VB.NETでラッパークラスを作成する場合はどうしたら良いでしょうか?
VB.NETの「Inherits」というのはJavaやC++で言う、「extends」宣言に当たるのでしょうか?
例えば、上記サンプルコード中のExcel.Workbooksクラス?のラッパークラスを作成する場合、
Inherits Excel.Workbooks
Public Class XlApp
〜
End Class
と記述すると「名前空間のステートメントが無効」と言われてしまいます。
Inherits を使った継承に関しては過去ログ検索『Inherits』
で色々引っかかると思います。サンプルも載せてあります。
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200408/04080006.txt
>名前空間のステートメントが無効
は書式が間違ってるので…書くとしたら
Public Class XlApp
Inherits Excel.Workbooks
End Class
ですが、そもそもクラスでないと継承できませんので
Public Class XlApp
Inherits Excel.ApplicationClass
End Class
ですかねぇ?。でもこの継承は…やった事無いので
何が起こるか予想が付きません。
同じような処理をクラスにして再利用するだけなら、
継承なんかしなくても、普通にクラスを作って関数で
対応できると思いますが?。
> ラッパークラスを作成してその中で開放する処理を記述して、
> コードの簡素化を図ろうかと考えていますが、
アンマネージリソースを解放させるためのラッパーを作る場合には、
『IDisposable インターフェイス』を実装させるのが一般的です。
(IDisposableには、Disposeというメソッドだけが定義されています)
Disposeメソッドに、アンマネージリソースの解放処理を書いておけば、
呼び出し側は、最後にDisposeメソッドを明示的に呼ぶだけで済みます。
また、IDisposableインターフェイスを実装する場合は、Disposeメソッドが
呼び出されなかった場合に備えて、Finalizeメソッドも実装するようにします。
なお、ラッパークラス側の実装としては、親オブジェクトがDisposeされたら、
子オブジェクトも連鎖的にDisposeさせるようにします。こうすれば、
オブジェクトが残ってしまうことはありません。
# ただ、それを実現させるためには、常に親階層のクラスが、
# 子階層のクラスを管理し続けなければなりませんけれどね。
ツイート | ![]() |