DOBON.NET DOBON.NETプログラミング掲示板過去ログ

Excelの解放

  • 題名: Excelの解放
  • 著者: KAN
  • 日時: 2007/12/01 20:21:55
  • ID: 21069
  • この記事の返信元:
    • (なし)
  • この記事への返信:
  • ツリーを表示
環境/言語:[Windows XP SP2 C# .NET 2.0]
分類:[.NET]

初めまして。VS2005 C#で記述しています。
下記の様に単純にエクセルのインスタンスを作成して、閉じるサンプルを
作ったのですが、エクセルが解放されずに残ってしまいます。
記述に不味い点がありますでしょうか。
終了時点では、オブジェクト型としてはリソースが残っていない様ですので
System.Runtime.InteropServices.Marshal.ReleaseComObjectは使用していません。

string Terget = System.IO.Path.GetTempPath() + "prt.xls";

Type ExcelPrgID = Type.GetTypeFromProgID("Excel.Application");
if (ExcelPrgID == null) return;

object objXL = Activator.CreateInstance(ExcelPrgID);
object objBook = objXL.GetType().InvokeMember("Workbooks", System.Reflection.BindingFlags.GetProperty, null, objXL, null);

objBook = objBook.GetType().InvokeMember("Open", System.Reflection.BindingFlags.InvokeMethod, null, objBook, new object[] { Terget });

objBook = objBook.GetType().InvokeMember("Close", System.Reflection.BindingFlags.InvokeMethod, null, objBook, null);
objXL = objXL.GetType().InvokeMember("Quit", System.Reflection.BindingFlags.InvokeMethod, null, objXL, null);
  • 題名: Re[1]: Excelの解放
  • 著者: じゃんぬねっと
  • 日時: 2007/12/02 17:37:54
  • ID: 21073
  • この記事の返信元:
  • この記事への返信:
  • ツリーを表示
■No21069に返信(KANさんの記事)
> 記述に不味い点がありますでしょうか。

記述と理論にまずい点がありそうです。

> 終了時点では、オブジェクト型としてはリソースが残っていない様ですので
> System.Runtime.InteropServices.Marshal.ReleaseComObjectは使用していません。

意味がよくわかりませんが、COM の参照カウントが発生しているので必要です。
じゃんぬねっとさん
レスポンスありがとうございます。

> 記述と理論にまずい点がありそうです。
> 意味がよくわかりませんが、COM の参照カウントが発生しているので必要です。

そうですね。リソースが残っているから解放されていないのですから記述がおかしいですよね。
では、順を追って。
まず、エクセルの解放状況はタスクマネージャでチェックしています。
コマンドボタンで記述ルーチンを実行すると、実行終了後も、Excel.exeが
残っていて、コマンドボタンを数回押すとその分excel.exeも増えていきます。
出来れば、処理が終わった時点で、excel.exeがタスクマネージャ上で消えて
くれればと思っています。

.ReleaseComObjectに関しては、objXLをQuitした後に記述しようとしたのですが、
「オブジェクトの型は __ComObject か、または __ComObject から派生しなければなりません。」とエラーが発生しました。
objXLをQuitした時点で、objBookの値はtrue,objXLの値はnullになっていました。

当初、下記の記述を最後に追加して、objXLとobjBookを解放してやれば良いと思っておりました。適切なCOM の参照カウントを減らす方法がありますでしょうか。
System.Runtime.InteropServices.Marshal.ReleaseComObject(objBook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(objXL);
理解できているおつもりかもしれませんが、失礼ながらたぶん理解できていないと思われます。
たとえば参照カウントをデクリメントする前に上書きされてしまっている参照がありますよね。
  • 題名: Re[4]: Excelの解放
  • 著者: るしぇ
  • 日時: 2007/12/03 21:43:38
  • ID: 21084
  • この記事の返信元:
  • この記事への返信:
  • ツリーを表示
2007/12/03(Mon) 21:47:30 編集(投稿者)


■No21083に返信(じゃんぬねっとさんの記事)
> 理解できているおつもりかもしれませんが、失礼ながらたぶん理解できていないと思われます。
がんばって具体的に書いてみた><

オブジェクト型とオブジェクトは意味が違います。
.NET側でオブジェクト型を使おうが、アーリーバインディングで
明示的な型を使おうが、Excel オブジェクトを参照する点は
同じです。

むしろ、明示的な型でプログラミングする練習をしたほうが
いいのでは?
[問題点1]Excel の構造を理解していない。
WorkBooks オブジェクトと WorkBook オブジェクトは別のもの
なのに同じ変数で受けてますよ?
# レイトバインディングのみしか使わないなら何とかなって
# しまいますけど、書かないようにすべきコードでしょう。

[問題点2]左辺と右辺に同じ参照変数を使っている。
参照カウンタは参照する毎にカウントアップされるので、解放
しないで上書きした時点でまずいと思うべきです。
提示されたコードを使うなら、引数に使っている objBook と左辺の
objBook は別々に解放する必要があると思います。
# 物理的に無理なので別変数を用意します。

[問題点3]無駄な処理?
C#で「遅延バインディング」を行うには、InvokeMember だった
気はするけど、オブジェクトを取得済みなのに
>objBook = objBook.GetType().InvokeMember("Close", System.Reflection.BindingFlags.InvokeMethod, null, objBook, null);
objBook.Close ではだめなの?
# 他の処理にも言えるけど。。。

C# は全く知らないけど、無駄な参照ばっかりして、参照カウンタを
あげまくってる気はする。。。

理解できてないと思います。そればかりか間違って解釈してます。
1.Excel の構造を理解し、
2.間接的にオブジェクトを参照するような命令は使わず、全て変数に受ける
3.参照した Excel オブジェクトは、全てを、その都度解放する
といった理解が必要です。

http://jeanne.wankuma.com/tips/programing/releasecom.html
とか、VBだけど、
http://hanatyan.sakura.ne.jp/dotnet/Excelflm.htm
あたりを一通り読んできてください。
■No21084に返信(るしぇさんの記事)
> がんばって具体的に書いてみた><

お、お疲れ様です...
私のサイトにも NG パターンが必要なのかもしれません。
  • 題名: Re[6]: Excelの解放
  • 著者: KAN
  • 日時: 2007/12/04 10:51:11
  • ID: 21087
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
2007/12/04(Tue) 11:40:42 編集(投稿者)


■No21083に返信(じゃんぬねっとさんの記事)
>たとえば参照カウントをデクリメントする前に上書きされてしまっている参照がありますよね。

> ■No21084に返信(るしぇさんの記事)
>>がんばって具体的に書いてみた><

皆さん、ありがとうございます。
特にるしぇさんの、丁寧な解説は目から鱗でした。

あまり深く考えずにあちこちのサイトから適当にサンプルを引っ張って
しまったのが敗因でした。特にオブジェクトの扱い方がいいかげんでした。

もう一度きちんと勉強し直します。本当にありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板