- - PR -
Excelオブジェクトの解放
投稿者 | 投稿内容 | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2005-10-12 19:27
VB.NET(2003)にてExcel(2002)の操作をしたいのですが、
プロセスが終了されずに困っています。 基本部分(Excel起動〜ファイル開く〜Excel終了)は、 http://www.bcap.co.jp/hanafusa/dotnet/Excelflm.htm を参考に問題なく動作しています。 これにExcelの名前の定義の追加操作をしたいのですが、 Excelのプロセスが残ってしまいます。 具体的には、下記ソースの★部分を有効にするとNGになります。 解決方法、ご存知の方いらっしゃいましたら、ご教授願います。 以下、ソース-------------------------------------------------------- 'COM オブジェクトへの参照を解放するプロシージャ(既存のファイルを開く場合も共用) Private Sub MRComObject(ByRef objCom As Object) 'COM オブジェクトの使用後、明示的に COM オブジェクトへの参照を解放する Try '提供されたランタイム呼び出し可能ラッパーの参照カウントをデクリメントします System.Runtime.InteropServices.Marshal.ReleaseComObject(objCom) Catch Finally '参照を解除する objCom = Nothing End Try End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim xlFilePath As String = Application.StartupPath & "\\work\\temp.xls" Dim xlBook As Excel.Workbook = xlBooks.Open(xlFilePath) Dim xlSheets As Excel.Sheets = xlBook.Worksheets Dim xlSheet0 As Excel.Worksheet = xlSheets.Item("sheet0") Dim xlSheet1 As Excel.Worksheet = xlSheets.Item("sheet1") Dim xlSheet2 As Excel.Worksheet = xlSheets.Item("sheet2") Dim xlSheet3 As Excel.Worksheet = xlSheets.Item("sheet3") Dim xlCells As Excel.Range Dim xlRange As Excel.Range Dim xlNames As Excel.Names = xlBook.Names '★ xlApp.Visible = False 'Excelを非表示 xlApp.DisplayAlerts = False '保存時の問合せのダイアログを非表示に設定 xlApp.ScreenUpdating = False ' cmd.Connection = Con cmd.CommandText = "SELECT DISTINCT COL1 FROM TAB WHERE COL1 IS NOT NULL" rdr = cmd.ExecuteReader Rcnt = 0 xlCells = xlSheet1.Cells Do While rdr.Read = True Rcnt = Rcnt + 1 xlRange = xlCells(Rcnt, 1) xlRange.Value = rdr.GetString(0) MRComObject(xlRange) 'xlRange の開放 Loop rdr.Close() MRComObject(xlCells) 'xlCells の開放 MRComObject(xlRange) 'xlRange の開放 xlSheet1.Visible = False xlApp.ActiveWorkbook.Names.Add(Name:="name1", RefersToR1C1:="=sheet1!R1C1:R" & Rcnt & "C1") '★ MRComObject(xlNames) 'xlNames の開放 '★ ・ ・ ・ xlSheet0.SaveAs(xlFilePath) 'ファイルに保存 '終了処理 MRComObject(xlSheet0) 'xlSheet の開放 MRComObject(xlSheet1) 'xlSheet の開放 MRComObject(xlSheet2) 'xlSheet の開放 MRComObject(xlSheet3) 'xlSheet の開放 MRComObject(xlSheets) 'xlSheets の開放 xlBook.Close(False) 'xlBook を閉じる MRComObject(xlBook) 'xlBook の開放 MRComObject(xlBooks) 'xlBooks の開放 xlApp.Quit() 'Excelを閉じる MRComObject(xlApp) 'xlApp を開放 End Sub ここまで-------------------------------------------------------- | ||||||||||||||||||||
|
投稿日時: 2005-10-12 19:50
解放し忘れているオブジェクト参照があるからです。
ダウト。 問題の原因となるのは
の行だけのはず。
使用したオブジェクト参照を漏れなく Marshal.ReleaseComObject() で解放すればよいです。 他の箇所では細かく参照の取得・解放を行っているのに対して、
の ActiveWorkbook と Names に関してはそれを怠っているから期待通りの動作が得られないのです。 | ||||||||||||||||||||
|
投稿日時: 2005-10-13 09:42
COM はこれくらい慎重に扱っても余りあるものです。(^-^;)
COM オブジェクトを解放する _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||||||||||||||
|
投稿日時: 2005-10-13 10:58
渋木宏明(ひどり)さん、じゃんぬねっとさん
返信ありがとうございます。 nameオブジェクトを解放すれば良さそうですが・・・ 試行錯誤してみます。 | ||||||||||||||||||||
|
投稿日時: 2005-10-13 11:42
違います。
と指摘しているのに、何故「name だけ」という結論に達するのでしょう?
「理解して、応用する」のが望ましいです。 でないと、似たようなことをする時に、同じような苦労をすることになります。 | ||||||||||||||||||||
|
投稿日時: 2005-10-13 14:37
渋木宏明(ひどり)さん、返信ありがとうございます。
ヘルプ(namesコレクションオブジェクト)を見ると、 Application +Workbooks (Workbook) +Names (Name) +Worksheets (Worksheet) +Names (Name) +Range +Name となっています。 現在、Namesオブジェクトを扱っていますが、 暗黙的にActiveWorkbookを参照していると考え、 ソースを次のように修正しました。 Dim xlActBook As Excel.Workbook = xlApp.ActiveWorkbook Dim xlNames As Excel.Names = xlActBook.Names Dim xlName As Excel.Name xlNames.Add(Name:="name1", RefersToR1C1:="=sheet1!R1C1:R" & Rcnt & "C1") xlName = xlNames.Item("name1") MRComObject(xlName) 'xlName の開放 MRComObject(xlNames) 'xlNames の開放 MRComObject(xlActBook) 'xlNames の開放 結果、プロセスが残ってしまっています。 どこの使い方(考え方)が悪いのか 教えてもらえませんか。
そうですね。 ご指摘、ありがとうございます。 | ||||||||||||||||||||
|
投稿日時: 2005-10-13 15:11
こんにちは、じゃんぬ です。
ActiveWorkbook と Names が暗黙的に参照されています。
えっと、xlNames.Add の戻り値を xlName に格納しないのは何故ですか? 参照カウントが 1 つ増えますよね? で、先にも書いたように Try 〜 Finally を使うことで構造化されて解放が確認しやすくなります。 ネストが深くなりすぎますから、実際にはコードの可読性は悪くなります。 でも、安全に解放されることの方が大切だと私は考えます。 Finally の恩恵は判りますよね? 後は組み方次第だと思います。 _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||||||||||||||
|
投稿日時: 2005-10-13 16:13
じゃんぬねっとさん、返信ありがとうございます。
変数xlNames宣言時と、xlNames.Add(こちらは解放不可)の 2カウントという意味ですよね?
VB.netは業務で使用したことが無い為、vb6のようにon errorで 記述していました。 ソースを次のようにしましたが、未だprocessが残ります。 他に暗黙的に参照されているのがあるのでしょうか? ---------------------------------------------------------------------- Dim xlActBook As Excel.Workbook = xlApp.ActiveWorkbook Try Dim xlNames As Excel.Names = xlActBook.Names Try Dim xlName As Excel.Name = xlNames.Add(Name:="name1", RefersToR1C1:="=sheet1!R1C1:R" & Rcnt & "C1") Try Finally If Not xlName Is Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(xlName) End If End Try Finally If Not xlNames Is Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(xlNames) End If End Try Finally If Not xlActBook Is Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(xlActBook) End If End Try ---------------------------------------------------------------------- |