- PR -

Excelオブジェクトの解放

投稿者投稿内容
まっく
会議室デビュー日: 2002/08/30
投稿数: 18
投稿日時: 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
ここまで--------------------------------------------------------
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2005-10-12 19:50
引用:

VB.NET(2003)にてExcel(2002)の操作をしたいのですが、
プロセスが終了されずに困っています。



解放し忘れているオブジェクト参照があるからです。

引用:

具体的には、下記ソースの★部分を有効にするとNGになります。



ダウト。

問題の原因となるのは

引用:

xlApp.ActiveWorkbook.Names.Add(Name:="name1", RefersToR1C1:="=sheet1!R1C1:R" & Rcnt & "C1") '★



の行だけのはず。

引用:

解決方法、ご存知の方いらっしゃいましたら、ご教授願います。



使用したオブジェクト参照を漏れなく Marshal.ReleaseComObject() で解放すればよいです。

他の箇所では細かく参照の取得・解放を行っているのに対して、

引用:

xlApp.ActiveWorkbook.Names.Add(Name:="name1", RefersToR1C1:="=sheet1!R1C1:R" & Rcnt & "C1") '★



の ActiveWorkbook と Names に関してはそれを怠っているから期待通りの動作が得られないのです。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-10-13 09:42
COM はこれくらい慎重に扱っても余りあるものです。(^-^;)

  COM オブジェクトを解放する

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
まっく
会議室デビュー日: 2002/08/30
投稿数: 18
投稿日時: 2005-10-13 10:58
渋木宏明(ひどり)さん、じゃんぬねっとさん
返信ありがとうございます。

nameオブジェクトを解放すれば良さそうですが・・・
試行錯誤してみます。

渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2005-10-13 11:42
引用:

nameオブジェクトを解放すれば良さそうですが・・・



違います。

引用:

ActiveWorkbook と Names に関してはそれを怠っているから



と指摘しているのに、何故「name だけ」という結論に達するのでしょう?

引用:

試行錯誤してみます。



「理解して、応用する」のが望ましいです。
でないと、似たようなことをする時に、同じような苦労をすることになります。

まっく
会議室デビュー日: 2002/08/30
投稿数: 18
投稿日時: 2005-10-13 14:37
渋木宏明(ひどり)さん、返信ありがとうございます。

引用:

引用:

ActiveWorkbook と Names に関してはそれを怠っているから



と指摘しているのに、何故「name だけ」という結論に達するのでしょう?



ヘルプ(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 の開放

結果、プロセスが残ってしまっています。

どこの使い方(考え方)が悪いのか
教えてもらえませんか。

引用:

引用:

試行錯誤してみます。



「理解して、応用する」のが望ましいです。
でないと、似たようなことをする時に、同じような苦労をすることになります。




そうですね。
ご指摘、ありがとうございます。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-10-13 15:11
こんにちは、じゃんぬ です。

引用:

まっくさんの書き込み (2005-10-13 14:37) より:

現在、Namesオブジェクトを扱っていますが、
暗黙的にActiveWorkbookを参照していると考え、
ソースを次のように修正しました。


ActiveWorkbook と Names が暗黙的に参照されています。

引用:

 xlNames.Add(Name:="name1", RefersToR1C1:="=sheet1!R1C1:R" & Rcnt & "C1")
 xlName = xlNames.Item("name1")


えっと、xlNames.Add の戻り値を xlName に格納しないのは何故ですか?
参照カウントが 1 つ増えますよね?

で、先にも書いたように Try 〜 Finally を使うことで構造化されて解放が確認しやすくなります。

ネストが深くなりすぎますから、実際にはコードの可読性は悪くなります。
でも、安全に解放されることの方が大切だと私は考えます。
Finally の恩恵は判りますよね?
後は組み方次第だと思います。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
まっく
会議室デビュー日: 2002/08/30
投稿数: 18
投稿日時: 2005-10-13 16:13
じゃんぬねっとさん、返信ありがとうございます。

引用:

えっと、xlNames.Add の戻り値を xlName に格納しないのは何故ですか?
参照カウントが 1 つ増えますよね?


変数xlNames宣言時と、xlNames.Add(こちらは解放不可)の
2カウントという意味ですよね?

引用:

で、先にも書いたように Try 〜 Finally を使うことで構造化されて解放が確認しやすくなります。

ネストが深くなりすぎますから、実際にはコードの可読性は悪くなります。
でも、安全に解放されることの方が大切だと私は考えます。
Finally の恩恵は判りますよね?


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
----------------------------------------------------------------------

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