- PR -

[ASP.NET]EXCELが終了しない

投稿者投稿内容
おくちn
会議室デビュー日: 2003/01/20
投稿数: 8
投稿日時: 2003-01-20 22:30
初めまして。
ASP.NETより、EXCELファイルを作成するアプリを開発しております。

ご質問なのですが、EXCELオブジェクトを作成し、処理した後で、オブジェクトを
破棄しても、EXCELが終了しません。(タスクマネージャでみると残っている)

以下がソースです。

Dim xl As Object

xl = CreateObject("Excel.Application")
xl.Workbooks.Add()

・・・Sheetの操作

xl.Application.DisplayAlerts = False
xl.ActiveWorkbook.SaveAs(FileName:=wkpath & wkexcelnm)
xl.Quit()
xl.Application.DisplayAlerts = True

xl = Nothing

よくわからないまま、最後に GC.Collect() を入れてみましたが、EXCELが終了
しませんでした。ご存じの方がいらっしゃいましたら、ご教授お願いします。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-01-21 08:57
引用:

おくちnさんの書き込み (2003-01-20 22:30) より:
初めまして。
ASP.NETより、EXCELファイルを作成するアプリを開発しております。

ご質問なのですが、EXCELオブジェクトを作成し、処理した後で、オブジェクトを
破棄しても、EXCELが終了しません。(タスクマネージャでみると残っている)

以下がソースです。

Dim xl As Object

xl = CreateObject("Excel.Application")
xl.Workbooks.Add()

・・・Sheetの操作

xl.Application.DisplayAlerts = False
xl.ActiveWorkbook.SaveAs(FileName:=wkpath & wkexcelnm)
xl.Quit()
xl.Application.DisplayAlerts = True

xl = Nothing

よくわからないまま、最後に GC.Collect() を入れてみましたが、EXCELが終了
しませんでした。ご存じの方がいらっしゃいましたら、ご教授お願いします。



 エクセルを起動したプログラムが終了すると、終了します。これは、CreateObjectで確保したオブジェクトが、CreateObjectを発行した*スレッド*によって参照されているため、ガベージコレクタがガベージではないと判断しているためと思われます。
 「やっぱりわからない、GCの動作」を参考にしてみてください。(直接的なタイトルでなくてすみません)
おくちn
会議室デビュー日: 2003/01/20
投稿数: 8
投稿日時: 2003-01-21 10:47
はじめまして。ご回答ありがとうございます。

「やっぱりわからない、GCの動作」を参考にさして頂き、プログラムを修正してみました
が、まだ、EXCELが終了しないみたいです。気持ち悪いのは、EXCEL出力処理が終了した後
もしばらく(10秒位)、EXCELのCPU使用率が100%近い値になっています。

先ほど、ご説明をかなり抜粋しましたので、再度、ご説明さして頂きます。

処理概要
ひな形のEXCELファイルのシート、新しいブックをコピーして、値をセットし新しいブッ
クを保存する。

Dim xl As Object
Dim booknm as String

xl = CreateObject("Excel.Application")

xl.Workbooks.Add()
booknm = xl.ActiveWorkbook.Name

With xl
.Workbooks.Open(AppPath & "Report.xls")
.Windows("Report.xls").Activate()
.Sheets("1-1").Select()
.Sheets("1-1").Copy(Before:=.Workbooks(booknm).Sheets(1))

.Workbooks("Report.xls").Close(False)

.Application.DisplayAlerts = False
.ActiveWorkbook.SaveAs(FileName:="C:\TEST.XLS")
.ActiveWorkbook.Close(False)

.Application.DisplayAlerts = True
.Quit()
End With

xl = Nothing
System.GC.Collect()

と言う具合に、教えて頂いたスレッドを参考にし、一部書き換えてみましたが、ダメで
した、その他に考えられる手段があれば、ご教授頂ければと思います。

rucio
ベテラン
会議室デビュー日: 2002/11/27
投稿数: 98
投稿日時: 2003-01-21 11:16
こんにちは。
私も興味があって試してみたのですが
前出の別スレッド「やっぱりわからない、GCの動作」の最後のJittaさんの書き込みにある「スレッド処理クラスの中でNothingにするだけでなく、スレッド処理クラス自身をNothingしてやらなければいけなかったようです。 」を参考にして作るとうまく開放できました。

具体的には次のようしてみたところExcelが終了されるのをタスクマネージャで確認できました。
Public Class Form1
Inherits System.Windows.Forms.Form

+Windows フォーム デザイナで生成されたコード

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim MyTest As New TestClass()

MyTest.Test("C:\Test.xls")
MyTest = Nothing

GC.Collect()

End Sub

End Class

Public Class TestClass

Public Function Test(ByVal FileName As String)

Dim xl As Object = CreateObject("Excel.Application")

xl.Workbooks.Add()
xl.ActiveWorkbook.SaveAs(FileName)
xl.Quit()

End Function

End Class
おくちn
会議室デビュー日: 2003/01/20
投稿数: 8
投稿日時: 2003-01-21 11:52
たびたび、申し訳ありません。

ご指摘通り、EXCEL出力部分をクラス可して、試してみましたが、ダメでした。
ちなみに、ASP.NETですので、VB.NETとは少々事情が違うみたいです。
EXCELはIUSR_コンピュータ名のユーザーが使用している事になっています。

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-01-21 12:11
おくちnさん

引用:

rucioさんの書き込み (2003-01-21 11:16) より:

前出の別スレッド「やっぱりわからない、GCの動作」の最後のJittaさんの書き込みにある「スレッド処理クラスの中でNothingにするだけでなく、スレッド処理クラス自身をNothingしてやらなければいけなかったようです。 」を参考にして作るとうまく開放できました。


これです。「スレッド処理クラス自身をNothingしてやらなければいけなかったようです」これがキーなのです。
 ご提示のソース中、Object型変数xlを定義したクラスがxlへの参照を保持している間は、xlによって間接的に参照されていたエクセルが「参照されている」と判断されるようなのです。自動変数であるにもかかわらず、プロシージャを抜けただけではxlへの参照は削除されないようです。おそらく、キャッシュのようなものではないかと思います。しかし、再度このプロシージャに制御が移り、CreateObjectによってxlの参照先が更新されると、前に参照していたオブジェクトは「解放」されるようです。

 rucioさんのソースを元に説明すると、

Dim MyTest As New TestClass()
...新しいTestClassオブジェクトを生成し、MyTestにそれへの参照を設定します。
MyTest.Test("C:\Test.xls")
...TestClass.Testにはいります。
Dim xl As Object = CreateObject("Excel.Application")
...ここでエクセルのオブジェクトが作られ、xlにそれへの参照が設定されます。
...操作は省略
xl.Quit()
...エクセルを終了します。
End Function
...ここでxlは自動変数のため消滅し、エクセルオブジェクトへの参照もはずれますが、
...エクセルオブジェクトを作成したTestClassオブジェクトは存続しています。
...このため、「TestClassオブジェクトが生成する可能性のあるオブジェクト」
...としてキャッシュされます。
...Button1_Clickプロシージャに戻って、
MyTest = Nothing
...これで、上で作ったオブジェクトへの参照がはずれ、
...TestClassオブジェクトが解放される準備ができました。
GC.Collect()
...GCを強制し、TestClassオブジェクトを解放します。
...このとき、「TestClassオブジェクトが生成する可能性のあるオブジェクト」も不要になり、
...エクセルオブジェクトも解放されます。

※注意※
あくまで私見であり、仕様ではありません。
おくちn
会議室デビュー日: 2003/01/20
投稿数: 8
投稿日時: 2003-01-21 12:40
ご丁寧なご回答、ありがとうございます。

ご指摘通り、処理をしております。
引用さして頂き、こちらで違う部分を修正致しますと。

Public Class Form1
Inherits System.Web.UI.Page
↑WEB Form

+Web フォーム デザイナで生成されたコード

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
↑Page_LoadイベントでEXCELファイルを出力

Dim MyTest As New TestClass()

MyTest.Test("C:\Test.xls")

***出力したEXCELファイルをリンク(Aタグ)した画面を表示

MyTest = Nothing

GC.Collect()

End Sub

End Class

Public Class TestClass

Public Function Test(ByVal FileName As String)

Dim xl As Object = CreateObject("Excel.Application")

xl.Workbooks.Add()
xl.ActiveWorkbook.SaveAs(FileName)
xl.Quit()

End Function

End Class

となっております。

rucio
ベテラン
会議室デビュー日: 2002/11/27
投稿数: 98
投稿日時: 2003-01-21 13:21
ASP.NETでは何か特段の事情があるのかと思い
こちらでもASP.NETで同様にプログラムを組んでみましたが
Excelはきちんと終了できています。

プログラムはおくちnさんのものとまったく同様です。
(リンクを生成する個所も書いてみました。)

ただし、ローカル環境でIISを動かして実行しました。
サーバー機にはExcelが入っていないので実験できません……。

スキルアップ/キャリアアップ(JOB@IT)