ゲーム馬鹿な日々


下手の横好きが格ゲーやネトゲをメインに、ゲームな日々を綴るブログ
by arc1230
プロフィールを見る
画像一覧
S M T W T F S
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

09/11/18 VBでExcelファイル編集。プロセス解放について。

さすがに2~3年ぶりにコーディングしてると、
気づかないこともある。

念願叶って、VB.NETっていうかVB2008での仕事をしているのです。

そのための備忘録。





でも、VB2008だろうが、コテコテのクラサバアプリケーションだったり。
しかも、帳票はExcelファイルで出力といった
無駄にエコ仕様。
「必要なファイルだけ出力する」
「出力する必要がなければ、紙を無駄にしない」
と言っているわりには、
正直、Excelでの帳票のが、絶対、開発工数かかると思うんだよな。

帳票を未だにExcelで出そうしているユーザがいるってだけでも、
オレにとっては、レアなユーザなんですけど・・・。

----------------------------------------------
話を戻して・・・。
VBでExcelを弄るときは、以下の点を注意すること。
※というか、注意というより徹底しろ。
 そうじゃないと、折角、動くものが出来ても、
 編集後にExcelプロセスが落ちないから、
 Windows側から直接Excelを起動できなくなる。

■Excelのマクロの記録でとったコードはそのまま使えない。
 超常識。
 よくあるのは、
 
 例  誤り ActiveSheet    正解 xlBook.ActiveSheet  

 この間違え。
 基本的に、バックグラウンドでファイルの中身を編集するので、
 ActiveSheetオブジェクトを使うほうが珍しい。
 逆に、ユーザに編集のExcelファイルの中身を見せたいなら、
 ActiveSheetオブジェクトを使うはあり。
 でも、あんまオススメしないし。オレが設計するならそんなんしない。
 ちなみに、シート名が分かっているなら、直接取得したほうがいい。

 xlSheet = xlBook.Worksheets("hoge")


■VB6.0との違い
 VB2008触って初めて気づいた。
 Excelを弄る際のオブジェクトの宣言記述が違う。

 VB6.0 の場合

  Dim xlApp  As Excel.Application
  Dim xlBook As Excel.Workbook
  Dim xlSheet As Excel.Worksheet

  Set xlApp = CreateObject("Excel.Application")
  Set xlBook = xlApp.Workbooks.Add
  Set xlSheet = xlBook.Worksheets(1)

 VB.NET の場合
  Dim xlApp As New Excel.Application
  Dim xlBooks As Excel.Workbooks = xlApp.Workbooks
  Dim xlBook As Excel.Workbook = xlBooks.Add
  Dim xlSheets As Excel.Sheets = xlBook.Worksheets
  Dim xlSheet As Excel.Worksheet = xlSheets.Item(1)

 つまりは、CreateObjectしなくて良くなったってこと。


■オブジェクトの解放
 ここから本題。
 帳票をExcelしているという部分で、
 オレが最もExcelがクソだと思っている部分。

 宣言して使わなくなったオブジェクト変数は、
 Marshal.ReleaseComObject() を実行して、
 オブジェクトインスタンスの解放を必ず行わなければならない。
 
 上の宣言の違い部分で記述した宣言であれば、
 
 xlApp、xlBooks、xlBook、xlSheets、xlSheet
 
 これらすべてを解放する必要がある。
 ちなみに、Nothingを代入することによる解放は出来ない。
 Marshal.ReleaseComObject() してから、その結果のオブジェクトに対して、
 Nothingを代入べき。

 こうしないと、Excelファイルを弄っている側のアプリケーションを終了しても、
 Excelプロセスが残り続けるというクソバカ仕様なので、
 絶対に解放を忘れないこと。

 ※余談:Excelプロセスが残ったままだと何が起きるか?
  その状態で、Excelを起動しても、Excelのメニューしか表示されない。
  しかも、メニュー自体も固まっているように見える。
  つまり、Excelは、同時2つ以上のプロセスを動かすことができない?

■Excel関連オブジェクトへのアクセス方法
 こんなところにまで頭を回す必要がある。
 上でも述べたように、VBAのコードはそのまま使えないが、
 大抵、罫線を引いたり、セルの書式を変更するロジックを調べるのに、
 マクロの記録を使うが、VBAのマクロの記述のままでは、VB2008は、
 「動く場合もあるが、Excelプロセスが居残り続ける」
 といった罠がある。

 たとえば、あるセルの色を指定するコードをマクロで記録してから、
 VB用に書き換えたとする。
 
 ※ここでは、sheetオブジェクトの取得等は省く。
 xlRange = xlCells(1,1)
 xlRange.Interior.Color = RGB(0, 255, 0)
  マクロの記録ではこのようにオブジェクトの取得を省いて、
  1lineでプロパティまでアクセスする傾向にある。
 
 この後、xlRangeオブジェクトの解放を行えば、いいように見えるが、
 それだけでは、Excelプロセスは落ちない。
 実際、コンパイルでもエラーにならなければ、
 Excelファイル側でもちゃんとセルに色は塗られるから質が悪い。

 何故xlRangeオブジェクトの解放では、ダメなのか。

 xlRange = xlCells(1,1)
 xlRange.Interior.Color = RGB(0, 255, 0) ←原因はココ

 ここにxlRangeオブジェクト以外の、もう1つのオブジェクトが隠れている。
 そのオブジェクトを解放しないといけない。

 xlRange = xlCells(1, 1)
 Dim xlInterior As Excel.Interior
 xlInterior = xlRange.Interior
 xlInterior.Color = RGB(0, 255, 0)
 
 VB上では、このように記述して、xlRangeオブジェクトとxlInteriorオブジェクトを
 解放しなければならない。
 つまり、あるオブジェクトの下にぶら下っているオブジェクトや
 プロパティにアクセスする際は、
 その親オブジェクト⇒子オブジェクト⇒孫オブジェクト⇒・・・⇒プロパティ
 と、すべてのオブジェクトを変数に取得していって、
 アクセスする必要があるということ。
 まぁ、というか、コンパイルエラーにしろよなって話なんだが。
 
 ループ処理で、同じRangeオブジェクトに上書きしてアクセスしている場合でも、
 ループを抜けてから、Rangeオブジェクトを解放してもダメ。
 1ループの終わる時点でその都度解放しないとハマる。

参考リンク:VBレスキュー

とりあえず、アレだ。
VBできる人間が、VBでExcelファイルの編集が
できると思われてるのがおかしい。
簡単だと思っている人間に限って、
この組み合わせでアプリ作ったことない人間だとオレは思う。
[PR]
by arc1230 | 2009-11-18 18:39 | プログラミング

ファン

ブログジャンル

画像一覧