プロが教えるわが家の防犯対策術!

 こんばんは,いつも勉強させていただいております.
どうぞよろしくお願いいたします.
 毎夜寝ずに.NETプログラミングでエクセルが動くのを楽しんでおりますが,
手元の参考書とネット検索だけではすっきりしない疑問点が数点あります.
どれか一つでもアドバイスいただけると非常に嬉しいです.
もしお詳しい方がいらっしゃいましたら,どうぞお願いいたします.


 「.」が沢山あるような深いプロパティ等を使いたい際(たとえばエクセルの
シート上にグラフが数個あり,これらの軸ラベルを変更するとき)
xlSheet.ChartObject.Chart.Axes(1).Axistitle.text = "test"
といきなり書くと解放できなくなると思うのですが,

(1)この一行を書くためだけに,すべての階層のObjectを作成・解放するものなのでしょうか???
  一応動作はするのですが,あまりこんな書き方を見かけないのですが.....

   Dim ChartObject As Object
   Dim ChartObjects = xlSheet.ChartObjects
   For Each ChartObject In ChartObjects
     ChartObject.Activate()
     Dim myChart As Object = ChartObject.Chart
     Dim myAxes As Object = myChart.Axes
     Dim myAxis1title As Object = myAxes(1).Axistitle
     Dim myAxis2title As Object = myAxes(2).Axistitle
       myAxis1title.text = "test"
       myAxis2title.text = "test"
     MRComObject(myAxis2title) : myAxis2title = Nothing
     MRComObject(myAxis1title) : myAxis1title = Nothing
     MRComObject(myChart) : myChart = Nothing
     MRComObject(myAxes) : myAxes = Nothing
     MRComObject(ChartObject) : ChartObject = Nothing
   Next
   MRComObject(ChartObjects) : ChartObjects = Nothing

(2)解放の順序については,下の階層からすべき? みたいなルールは特に無いのでしょうか.

     'たとえば↓みたいに下の階層から解放するか,
     MRComObject(myAxis1title) : myAxis1title = Nothing
     MRComObject(myAxes) : myAxes = Nothing
     MRComObject(myChart) : myChart = Nothing

     'もしくは↓みたいに上の階層から解放するか
     MRComObject(myAxis1title) : myAxis1title = Nothing
     MRComObject(myAxes) : myAxes = Nothing
     MRComObject(myChart) : myChart = Nothing

(3)下のコードだとぜんぜん問題ないんですが,
     Dim ChartObject As Object
     Dim ChartObjects = xlSheet.ChartObjects
     MRComObject(ChartObject) : ChartObject = Nothing
     MRComObject(ChartObjects) : ChartObjects = Nothing

   次のようにFor,Nextを入れるだけでExcelが解放されなくなります.
     Dim ChartObject As Object
     Dim ChartObjects = xlSheet.ChartObjects
     For Each ChartObject In ChartObjects

       MRComObject(ChartObject) : ChartObject = Nothing
     Next
     MRComObject(ChartObjects) : ChartObjects = Nothing

   この現象に一番困っております.もし何かお気づきになることがございましたら,
   是非ともアドバイスしてやってください.

(4)Excel解放のタイミングが,同じプログラム実行時でも弱冠異なるのですが,
   これはよくある現象なのでしょうか?それともコーディングに問題が???
    たとえば,
       Excel操作 →解放 →msgbox("終わり")
   としたときに,メッセージボックスのOKをわざと押さずに待機していると
   OKを押すまでExcel.Exeが解放されない時もあれば,押す前に一瞬で消える時もあります.



  どれか一つでもアドバイスいただけるようでしたら,是非よろしくお願いします.
 また上記コードの書き方に何か些細な突っ込みでもございましたら,いただければ嬉しいです.
 なにとぞお願いいたします.

A 回答 (3件)

>(1)この一行を書くためだけに,すべての階層のObjectを作成・解放するものなのでしょうか???


  一応動作はするのですが,あまりこんな書き方を見かけないのですが.....

そういうものだと思います。
VB6のときのほうが簡単でしたよね。

Vistual Studio Office Editionのような名前のものを使ってください。

>(2)解放の順序については,下の階層からすべき? みたいなルールは特に無いのでしょうか.

もちろんです。
下から開放しなければ、MRComObjectが開放対象を正しく特定できません。

>3)下のコードだとぜんぜん問題ないんですが,
Dim xlApp As Object = CreateObject("Excel.Application")
Dim xlBooks As Object = xlApp.Workbooks
Dim xlBook As Object = xlBooks.Open(ExcelPath)
Dim xlSheets As Object = xlBook.Worksheets
Dim flg As Short = 0

For Each sht As Object In xlSheets
MRComObject(sht)
Next
MRComObject(xlSheets) 'xlSheets の解放
Try
xlBook.Save()
xlBook.Close(False) 'xlBook を閉じる
Catch ex As Exception

End Try

MRComObject(xlBook) 'xlBook の解放
MRComObject(xlBooks) 'xlBooks の解放
xlApp.Quit() 'Excelを閉じる
MRComObject(xlApp) 'xlApp を解放
ちゃんと消えます。
sheetから書くと、bookあたりが自動的に?作られてしまうのではないでしょうか?

>(4)Excel解放のタイミングが,同じプログラム実行時でも弱冠異なるのですが・・・

どうでしょうか?
さほど大きくづれることはないはずです。
    • good
    • 0
この回答へのお礼

 AKARI0418 様
 どうもありがとうございます.なんとすべての質問にご回答いただけますとは.
ご親切にどうもありがとうございます.

>(1)
>そういうものだと思います。
>VB6のときのほうが簡単でしたよね。
 一発ですっきりしました.どうもありがとうございます.
 VB6は触ったことがございません...VB6のコードを拾ってきて
.NETに直せないことはたまにございますが...
ずっとFortranオンリーで,何週間も数値計算して数字の羅列を吐き出すのが
この世のプログラムのすべてと思い込んでおりましたが,
.NETに始めて触れて取りつかれて毎晩ワクワクいるヘタレでございます.
 あまりこういう書き方に触れたことがないということは
まだまだ修行と検索量が足りないのかもしれませんね.
どうもありがとうございます.

>(2)
>もちろんです。
>下から開放しなければ、
 どうもありがとうございます.すっきりしました.
ネットで必死に検索をかけておりますと,たまにxlAppから
解放しているコードを見かけますので,????と.
 お詳しい方にアドバイスいただけて良かったです.

>(3)
 コードでご確認までいただきどうもありがとうございます.
 ご指摘いただいた通り,sheetあたりの宣言文をもう少し練ってみます.
どうもありがとうございます.

>(4)さほど大きくづれることはないはずです。
 ご回答をいただいてから考えておりましたが,どうも私の
コーディングが下手なせいでもともと解放されにくいプログラムを
実行したときに発生している現象のようでございます.
おそらくきちんとしたコードの場合はAKARI0418様のおっしゃる通りに
なるのだと.というかなるはずですよね.

 ご親切に沢山のアドバイスをいただけて助かります.
本当にどうもありがとうございました.

お礼日時:2009/05/27 20:23

参考になると思います。


http://hanatyan.sakura.ne.jp/dotnet/Excel03.htm

きちんとすべての対象にReleaseComObjectを呼んでいるのであれば、
GC.Collect()は必要ないはずです。

GC.Collect()を行わなければ、EXCELが残ってしまうというのは、開放もれがあるはずです。

クラスを経由して行っている場合はその親クラスにあたるインスタンスに対しても、ReleaseComObjectが必要です。

むやみにガベージコレクタに対して、Collectを発行するべきではありません。

GCはジェネレーション管理を行っており、Collectにより世代がどんどん増えていってしまい負荷がかかります。
http://www.atmarkit.co.jp/fdotnet/dotnettips/021 …
    • good
    • 0
この回答へのお礼

 AKARI0418 様
 ご親切にどうもありがとうございます.

 自分のコードをすべて,リンクしていただいたページの書き方に直したところ
コードの半分が解放できました.どうもありがとうございます.
自分の思い込みで勝手に解放できないように修正してしまっていたようです.
今までは,質問文にかかせていただいたような
   Dim xlSheet As Excel.Worksheet
   Dim ChartObject As Object
   Dim ChartObjects = xlSheet.ChartObjects
   For Each ChartObject In ChartObjects
     Dim myChart As Object = ChartObject.Chart
     Dim myAxes As Object = myChart.Axes
     Dim myAxis1title As Object = myAxes(1).Axistitle
という書き方をしておりましたのを,花ちゃんのようにExcel.Axisとして解放されました.
   Dim MyAxis As Excel.Axis
   Dim MyAxes As Excel.Axes
   MyAxes = MyChart.Axes
   For Each MyAxis In MyAxes

 何故か前者のような書き方でも解放されている個所もありますが,
すべて後者に直しました.
 以前参考書か何かで「コードの途中でExcel.~と書くと知らないうちに2つ目の
Applicationオブジェクトを参照して~解放できなくなる.」というのを
読んだ覚えがありまして,コードをすべて前者のように書き換えておりましたのが原因のようです.
 ブラウザの履歴にも残っておりましたが,まったく目が届いておりませんでした.

 非常に沢山のアドバイスをいただきどうもありがとうございました.
現時点でもまだ解放できない部分がありますが,おそらく別の要因だと思われるので,
また別スレッドで質問させていただきます.

 本当にご親切にどうもありがとうございました.

お礼日時:2009/05/30 13:58

そのプロシージャから抜ける段階で


GC.Collect()
を実行してみましょう

これの実行で参照の開放を忘れていなければプロシージャを抜けた段階でExcelのタスクは消滅するようですよ

単純に workbooksコレクションを取得し開放しただけでも
Exeが実行中はExcelのタスクが残ってしまうようです
GC.Collect()を実行すると End Sub を実行後 タスクが消えました^^
Excel.Application型の変数はローカル変数で検証ですが ・・・

当方の環境 VB2005 + Excel2003
    • good
    • 0
この回答へのお礼

 これはなんとredfox63 様.

 先日も2度ほどアドバイスいただいております,わたくしcamputerと申します.
閲覧してくださりましてどうもありがとうございます.



 アドバイスいただいたとおりGC.Collect()を早速入れてみたところ,見事に消えました.
非常ーーーーーーーーに嬉しいです.どうもありがとうございます.
お手元の環境で試験してくださったようで,本当にどうもありがとうございます.

 念のため,今後同じ問題を抱えて閲覧される方のために書いておきますと,
私の環境
 Vista,VB2008,Excel2007
でもこのやり方で解放されました.

 しかしこれでようやく解放かと大喜びまして次のようにaxesまで
3つのオブジェクトを追加したらまた解放不可に........
Dim ChartObject As Object
Dim ChartObjects = xlSheet.ChartObjects
  For Each ChartObject In ChartObjects
  ChartObject.Activate()
  Dim myChart As Object = ChartObject.Chart
  Dim myChartTitle As Object = myChart.ChartTitle
  Dim myAxes As Object = myChart.Axes()

  MRComObject(myChartTitle) : myChartTitle = Nothing
  MRComObject(myChart) : myChart = Nothing
  MRComObject(myAxes) : myAxes = Nothing
  MRComObject(ChartObject) : ChartObject = Nothing
Next
MRComObject(ChartObjects) : ChartObjects = Nothing

 GC.Collect()で検索してひっかかるよく似たコード(GC.WaitForPendingFinalizers()とか)を
何個かプロシージャ最後に追加してみましたがうまくいきません...
 これについては別質問になりそうですので,今晩自分で考えます.

 この解決方法は自分では見つけられなかったと思います.
閲覧していただけてよかったです.
 本当にどうもありがとうございました.
                           camputer

お礼日時:2009/05/27 21:07

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!