none
CreateObject関数で作成したExcelオブジェクトのプロセスを破棄したい。 RRS feed

  • 質問

  • お世話になります。

    VB.NET2005にて、CreateObject関数を使用して、以下のコードを作成しました。

     Dim objExcel As Object

     objExcel = CreateObject("Excel.Application")

     objExcel.WorkBooks.Open(fileName)

    ' *****各種セル操作*****

    objExcel.ActiveWorkBook.SaveAs(fileName:=fileName)

    objExcel.WorkBooks(bookName).Close(SaveChanges:=False)

    objExcel.Application.Quit()

    以上にて、Excelブック呼出 ⇒ 各種セル変更 ⇒ 上書き保存 ⇒ Excel終了 という処理をしているのですが、
    プログラム動作上は、objExcel.Application.Quit() 実行後に、Excelは閉じられるのですが、
    タスクマネージャで実行中のプロセスを見ると、"EXCEL.EXE"がメモリ上に残ったままになっています。
    このプロセスは、上記コードを呼び出したフォーム画面を閉じても残っており、アプリケーションを終了した時点で破棄されるようです。
    また、objExcel.WorkBooks.Open(fileName) にて呼び出したExcelブックを手動で閉じた場合もプロセスは残ったままです。

    今までも気にはなっていましたが、特に不具合も無かったので、そのまま運用していましたが、今回、あるパネルコンピュータ(OS:Windows2000)に
    アプリケーションをインストールしたところ、2回目以降のobjExcel.WorkBooks.Open(fileName)の実行時に、Excelが完全に開かないエラーが発生
    するようになりました。対処方法を検討したのですが、どうやら先の"EXCEL.EXE"がプロセス実行中だとエラーが発生することが分かりました。
    ちなみに、今回はレイトバインディングでやっていますが、Excelタイプライブラリを使用したアーリーバインディングでも、"EXCEL.EXE"プロセスは残ったままでした。

    つきましては、プログラムで明示的にEXCEL.EXE"のプロセスを破棄する方法を探しています。
    どなたか御存知の方は御教授くださると助かります。
    以上、宜しくお願いいたします。






    2009年8月8日 1:22

回答

  • 以上にて、Excelブック呼出 ⇒ 各種セル変更 ⇒ 上書き保存 ⇒ Excel終了 という処理をしているのですが、
    これだけの処理をしているということはWorkBooksオブジェクト,WorkBookオブジェクト,RangeオブジェクトといったCOMオブジェクトにもアクセスしているはずですが、それらに対してはReleaseComObjectを行っていますか?
    それでもプロセスが終了しないのでしたら、実際のソースを見ないことにはどこで開放漏れしているかはわかりません。

    処理をコメントアウトして少しずつ実行させて、どこで開放漏れが起きているか調べられることをお勧めします。

    2009年8月8日 8:37

すべての返信

  • .Net FrameworkではCOMオブジェクトは自動では開放してくれません。
    そのため、ExcelのプロセスははCOMオブジェクトが利用中なので終了しなくなります。
    #レイトバインディング、アーリーバインディングは関係ありません。

    COMオブジェクトの開放にはSystem.Runtime.InteropServices.Marshal.ReleaseComObject(objExcel)のようにを実行します。
    取得したCOMオブジェクトの全てに対してこのような処理が必要です。

    詳しくは「EXCEL ReleaseComObject」をキーワードにして検索するとサンプルはたくさん出てくるでしょう。
    2009年8月8日 4:13
  • ありがとうございます。

    以下のコードで試したところ、

          Dim retValue As Integer

          Do

            retValue = Marshal.ReleaseComObject(objExcel)

          Loop Until retValue = 0

    objExcel.WorkBooks.Open(fileName) の実行前だとプロセスを終了できるのですが、
    一度でもExcelブックを開く処理をした後では、上記コードの実行後でもプロセスは残ったままでした。
    ※ちなみに、retValueの値が0になって終了しているのにもかかわらずです??

    もしかすると、VB6の時代に使われていた、Win32APIの関数を使って、クラス名称"XLMAIN"のインスタンスを
    破棄するコードを書かなければならないのかも知れません。

    御存知の方がおられたら、情報を頂けると幸いです。






    2009年8月8日 7:47
  • 以上にて、Excelブック呼出 ⇒ 各種セル変更 ⇒ 上書き保存 ⇒ Excel終了 という処理をしているのですが、
    これだけの処理をしているということはWorkBooksオブジェクト,WorkBookオブジェクト,RangeオブジェクトといったCOMオブジェクトにもアクセスしているはずですが、それらに対してはReleaseComObjectを行っていますか?
    それでもプロセスが終了しないのでしたら、実際のソースを見ないことにはどこで開放漏れしているかはわかりません。

    処理をコメントアウトして少しずつ実行させて、どこで開放漏れが起きているか調べられることをお勧めします。

    2009年8月8日 8:37
  • 回答ありがとうございます。

    確かに、objExcelにしかReleaseComObjectを実行していませんでした。

    WorkBooksオブジェクト,WorkBookオブジェクト,Rangeオブジェクトの使用に関しては、
    objExcelの下位オブジェクトとして記述していましたので、それぞれにReleaseComObjectが必要とは
    気付きませんでした。

    それぞれを単独のオブジェクトとして作成して、各種処理を実行後に、個別にReleaseComObjectを適用して見ます。

    2009年8月8日 8:56
  • objExcel.WorkBooks.Open(fileName) の実行後に、WorkBooksオブジェクトに対してReleaseComObjectを適用すると、
    Excelプロセスが終了できました。

    大変助かりました。今後とも宜しくお願いいたします。
    2009年8月8日 10:11