Visual Basic 6.0 テクニック
VB6対応

 

Visual Basic 中学校 > VB6 テクニック >

15.消えないExcelのプロセス

 

今回はVBからExcelを操作しているときにExcelのプロセスが残ってしまう現象(Excelが終了しない現象)とその対処法について説明します。従って他の回と違って「VBで○○をする方法」を解説したりはしません。

この現象は知る人ぞ知る現象なのですがVBからExcelを操作する人の多くが体験したことがあって、しかもはっきりとした説明がなかなかないので私がマイクロソフトに代わってここに書き記すことにしました。

この回の要約
  • 正しく処理しないとExcelのプロセスは終了しない。
  • ApplicationオブジェクトはQuitしなければならない。
  • WorkBookオブジェクトはCloseしなければならない。
  • Excel所属のオブジェクトは破棄しなければならない。
  • Excel. と書く場合は要注意。
  • いきなりプロパティを書いてはいけない。

 

1.現象の確認

 

まず、この現象を発生させて見ましょう。ただ急いで結論だけ知りたい方はこの節は読み飛ばしてしまって構いません。

後で紛らわしいことになるのでもしExcelを開いている場合はすべて閉じておいてください。その作業が終わったら次のプログラムを実行してみてください。

Private Sub Command1_Click()

Dim ExcelApp As Object 'Excel.Application

Dim Book As Object 'Excel.Workbook

Dim Sheet As Object 'Excel.Worksheet

Set ExcelApp = CreateObject("Excel.Application")

Set Book = ExcelApp.Workbooks.Add

Set Sheet = Book.Worksheets(1)

Sheet.Range("B5").Value = "Hello!"

Book.SaveAs("C:\VBExcel.xls")

End Sub

■リスト1:悪い例

このプログラムはCドライブにVBExcel.xlsというファイルを作成して、1枚目のシートの B5 に Hello! と書き込みます。さて、実行したらプログラムを終了させてください。

終了させたらタスクマネージャを開いて「プロセス」の一覧を見てみると、Excel と表示されているのが分かります。Excelは一つも起動させていないはずなのにおかしいですよね。 ここはとりあえず、タスクマネージャからExcelを終了させてください。

注意:Windows95, 98, Meで実行している場合はタスクマネージャは使用できませんが、眼に見えないだけでこの現象は発生しています。

念のためできあがったxlsファイルを開いてみると確かにセルB5にHello!と書き込まれているのが分かりますから、プログラム自体は正常なようです。

なおこの時、Excelの表示がおかしい場合は、さきほど実行したプログラムを終了させてないかタスクマネージャでExcelを終了させていない可能性があります。

さて、これが冒頭でも言った現象なのです。

 

2.原因と対策

 

この現象はすべてのApplicationオブジェクトを終了していない場合に発生します。

これは(私の思いつく限りでは)次のどれかの場合です。

2−1.Excel.ApplicationオブジェクトのQuitメソッドを使用していないとき。

例:このコードはExcelのプロセスが残ります。

Private Sub Command1_Click()

Dim ExcelApp As Object 'Excel.Application

Dim Book As Object 'Excel.Workbook

Dim Sheet As Object 'Excel.Worksheet

Set ExcelApp = CreateObject("Excel.Application")

Set Book = ExcelApp.Workbooks.Add

Set Sheet = Book.Worksheets(1)

Sheet.Range("C3").Value = "こんにちは"

Book.SaveAs("C:\Case1.xls")

End Sub

■リスト2:悪い例

このコードを修正するには、処理が終わった後にExcelApp.Quitを追加します。

例:このコードは正しくExcelのプロセスが終了します。

Private Sub Command1_Click()

Dim ExcelApp As Object 'Excel.Application

Dim Book As Object 'Excel.Workbook

Dim Sheet As Object 'Excel.Worksheet

Set ExcelApp = CreateObject("Excel.Application")

Set Book = ExcelApp.Workbooks.Add

Set Sheet = Book.Worksheets(1)

Sheet.Range("C3").Value = "こんにちは"

Book.SaveAs("C:\Case1.xls")

ExcelApp.Quit

End Sub

■リスト3:良い例

 

2−2.WorkBookオブジェクトを閉じていない場合

例2のようにExcel.Quitを使用していればWorkBookオブジェクトを明示的に閉じる必要はないようなのですが、逆にExcel.QuitがなくてもWorkBookオブジェクトを正しく閉じればExcelのプロセスは終了するようです(私もこの辺はあまり自信がありません)。

たとえば、リスト2は次のリスト4のように末尾にWorkBookオブジェクトを閉じる処理を追加しても正しく動作します。

例:このコードは正しくExcelのプロセスが終了します。

Private Sub Command1_Click()

Dim ExcelApp As Object 'Excel.Application

Dim Book As Object 'Excel.Workbook

Dim Sheet As Object 'Excel.Worksheet

Set ExcelApp = CreateObject("Excel.Application")

Set Book = ExcelApp.Workbooks.Add

Set Sheet = Book.Worksheets(1)

Sheet.Range("C3").Value = "こんにちは"

Book.SaveAs("C:\Case1.xls")

Book.Close

End Sub

■リスト4:良い例

但し、後々混乱を招くのでWorkBookオブジェクトを閉じる処理とApplicationオブジェクト閉じる処理(Quit)の両方を常に書き記すようにすべきです。

 

2−3.知らないうちに2つ目のApplicationオブジェクトを参照した場合

これはExcelに参照設定している場合しか起きません。Excelに参照設定しているかどうかは[プロジェクト]メニューの[参照設定]で確認してみてください。

例:このコードはExcelのプロセスが残ります。

Private Sub Command1_Click()

Dim ExcelApp As Object 'Excel.Application

Dim Book As Object 'Excel.Workbook

Dim Sheet As Object 'Excel.Worksheet

Set ExcelApp = CreateObject("Excel.Application")

Set Book = Excel.Workbooks.Add

Set Sheet = Book.Worksheets(1)

Sheet.Range("A4").Value = "こんにちは"

Book.SaveAs("C:\Case3.xls")

Book.Close

ExcelApp.Quit

End Sub

■リスト5:悪い例

この例の悪いところはExcel.Workbooks.Addです。これをExcelApp.Workbooks.Addにすればこの現象は発生しません。

例5:このコードは正しくExcelのプロセスが終了します。

Private Sub Command1_Click()

Dim ExcelApp As Object 'Excel.Application

Dim Book As Object 'Excel.Workbook

Dim Sheet As Object 'Excel.Worksheet

Set ExcelApp = CreateObject("Excel.Application")

Set Book = ExcelApp.Workbooks.Add

Set Sheet = Book.Worksheets(1)

Sheet.Range("A4").Value = "こんにちは"

Book.SaveAs("C:\Case3.xls")

Book.Close

ExcelApp.Quit

End Sub

■リスト6:良い例

なぜ、こういうことが起きるかというと、「Excel.」で参照した場合Excelは自動的に新しいApplicationオブジェクトを作成してそれに対して命令を実行するからです。しかも、その新しいApplicationオブジェクトに対するQuitはどこにもないのでExcelが残るのです。

一方ExcelAppとした場合は、最後に明示的にExcelApp.Quitがあるので問題ありません。

 

2−4.暗黙の参照をしている場合

これもExcelに参照設定している場合しか起きません。Excelに参照設定しているかどうかは[プロジェクト]メニューの[参照設定]で確認してみてください。

例:このコードはExcelのプロセスが残ります。

Private Sub Command1_Click()

Dim ExcelApp As Object 'Excel.Application

Dim Book As Object 'Excel.Workbook

Dim Sheet As Object 'Excel.Worksheet

Set ExcelApp = CreateObject("Excel.Application")

Set Book = ExcelApp.Workbooks.Add

Set Sheet = Book.Worksheets(1)

Range("D1").Value = "こんにちは"

Book.SaveAs("C:\Case4.xls")

Book.Close

ExcelApp.Quit

End Sub

■リスト7:悪い例

この例の悪いところは

Range("D1").Value = "こんにちは"

です。この部分は

Sheet.Range("D1").Value = "こんにちは"

と書かなければいけません。

正しい例は、リスト6と同じです。

どうしてこれがいけないかというと、いきなりRangeと書いた場合、どのWorkSheetRangeプロパティなのか明確ではないからです。この場合、VBは勝手に解釈して、新しいWorkSheetオブジェクトを作成して割り当てているようなのです(私もよくわからないのですが…)。

多分、この新しいWorkSheetオブジェクトにはそのときアクティブなワークシートが当てられているようなので結果は変わらないのですが、そのWorkSheetオブジェクトを暗黙裡に生成したApplicationオブジェクトを閉じる処理がどこにもないのでこのような現象が発生してしまうようです。

 

2−5.オブジェクトを破棄していない場合

これは複雑なアプリケーションほどありえるケースです。この例がリスト6(良い例)とほとんど同じという点にも注意を払ってください。

例:このコードはExcelのプロセスが残ります。

Dim ExcelApp As Object

Private Sub Command1_Click()

    Dim Book As Object
    Dim Sheet As Object

    Set ExcelApp = CreateObject("Excel.Application")

    Set Book = ExcelApp.WorkBooks.Add
    Set Sheet = Book.WorkSheets(1)

    Sheet.Range("D2") = "VBとExcelは親和性が高い"

    Book.SaveAs ("C:\Case5.xls")
    Book.Close
    ExcelApp.Quit

End Sub

■リスト8:悪い例

この例でExcelのプロセルが残るのは Excel.Applicationオブジェクトが破棄されていないからです。この例ではExcel.Applicationオブジェクトはモジュールレベルで宣言している変数ExcelAppで表現していますから、プロシージャの実行が終了しただけでは自動的に破棄されません。

リスト6の場合はExcel.Applicationオブジェクトがプロシージャ内で宣言されていたのでプロシージャの実行が終了した時点で自動的に削除されます。

リスト8のようにプロシージャ外のExcelオブジェクト(ApplicationオブジェクトやWorkBookオブジェクトなどすべてのオブジェクト)を使用している場合にExcelのプロセスを終了させるには明示的にオブジェクトを破棄する必要があります。

オブジェクトを明示的に破棄するには次のようにします。

Set ExcelApp = Nothing

これを組み込んだ正しい例は次の通りです。

Dim ExcelApp As Object

Private Sub Command1_Click()

    Dim Book As Object
    Dim Sheet As Object

    Set ExcelApp = CreateObject("Excel.Application")

    Set Book = ExcelApp.WorkBooks.Add
    Set Sheet = Book.WorkSheets(1)

    Sheet.Range("D2") = "VBとExcelは親和性が高い"

    Book.SaveAs ("C:\Case5.xls")
    Book.Close
    ExcelApp.Quit

    Set ExcelApp = Nothing

End Sub

■リスト9:良い例

 

2−6.その他の注意点

前にも書きましたが「この現象はすべてのApplicationオブジェクトを終了していない場合に発生します。

たとえば、自分で複数のApplicationオブジェクトを記述することができますが、それらすべてを終了させなければExcelのプロセスは残ります。

この現象が発生して困っている場合は、どこかに終了していないApplicationオブジェクトはないか、または暗黙裡に生成されているApplicationオブジェクトはないかに気を配ってみてください。

 

3.要するにどうすればよいか

 

ケースごとにいちいち確認するのは大変なのでVBからExcelを操作する際のガイドラインを作ってみました。冒頭に書いてあることとほとんど重複しているのですがこの通りにプログラムしていればExcelのプロセスが残って困ることはないはずです。

1.Applicationオブジェクトは必ず Quit する。

2.WorkBookオブジェクトは必ず Close する。

3.宣言以外の場所で Excel. と書いてはいけない。

4.参照は必ず宣言しているオブジェクトから書き始める。

× 悪い例: Selection.Value = "こんにちは!"

○ 良い例: ExcelApp.Selection.Value = "こんにちは!"

5.プロシージャ外で宣言しているオブジェクトは必ずNothingを使って破棄する。

 

また、以上説明したことを簡単に表にまとめておきます。残念ながらこれで完全とはいえません。この他のケースもあるかもしれません。

原因 解決方法 悪い例 良い例
Quitを使っていない。 Quitを使う。 リスト2 リスト3
ワークブックを閉じていない。 Closeを使う。 リスト2 リスト4
Excel. で直接参照している。 自分で宣言したApplicationオブジェクトを使う。 リスト5 リスト6
参照なしでいきなりプロパティを使っている。 きちんと参照を書く リスト7 リスト6
オブジェクトを破棄していない。 Set XX = Nothing を使ってオブジェクトを破棄する。 リスト8 リスト9