- - PR -
.netからのExcel操作によるプロセスに関して
1
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2008-09-29 18:20
お世話になります。ゆうと申します。
VB.NET(visualstudio2005)からCOMオブジェクトを利用して、 Excelを操作しています。 掲示板を色々見せて頂き、なんとか進めていたんですが、 何とも解決できないようなことが起きており、 どなたか経験があれば教えて頂きたいと思い、投稿させてもらいました。 ソースを記載していますので長いですが、どなたか宜しくお願い致します。 [現象] 後述のソースにてExcelを操作している。 Excel操作のみであればプロセスも残らず問題無。 しかし空の変数(文字型)を追加(※1)したところで、 プロセスが残っていることに気づき、その変数を削除したところ、 正常動作した。 [ソース] ''==================================== '' 変数宣言 ''==================================== '' エクセル関連 Dim lo_xlApp As Excel.Application = Nothing Dim lo_xlBooks As Excel.Workbooks = Nothing Dim lo_xlBook As Excel.Workbook = Nothing Dim lo_xlSheets As Excel.Sheets = Nothing Dim lo_xlSheet As Excel.Worksheet = Nothing Dim lo_PageSetup As Object = Nothing Dim lo_range As Excel.Range = Nothing Dim lo_xlBorders As Excel.Border = Nothing Dim lo_cells As Object = Nothing Dim lo_font As Object = Nothing '' 日付関連 Dim ls_start_date As String = "" Dim ls_end_date As String = "" Dim lio_culture As CultureInfo = New CultureInfo("ja-JP", True) lio_culture.DateTimeFormat.Calendar = New JapaneseCalendar() '' SQL関連 Dim ls_SQL As String = "" '' SQL Dim lo_DataTable As DataTable = Nothing '' SQLの戻り値 Dim li_SqlCount As Integer = 0 '' SQLの実行件数 '' その他 Dim ls_tax As String = "" '' 消費税 '' ※1 Dim aaa As String = "" Dim bbb As String = "" '' ※1 中略 ''==================================== '' 起動処理 ''==================================== '' Excelインスタンス化 lo_xlApp = New Excel.Application '' ワークブックを設定 lo_xlBooks = lo_xlApp.Workbooks '' ブックを追加 lo_xlBook = lo_xlBooks.Add '' ワークシートを追加 lo_xlSheets = lo_xlBook.Worksheets '' ワークシートを設定 lo_xlSheet = lo_xlSheets.Item(1) ''-------------- '' ページ設定 ''-------------- lo_PageSetup = lo_xlSheet.PageSetup With lo_PageSetup .Orientation = ex_xlLandscape .ZOOM = 75 .LeftMargin = 0 .RightMargin = 0 End With 中略(内容を記載) ''==================================== '' 保存処理 ''==================================== '' 保存時の問合せのダイアログを非表示に設定 lo_xlApp.DisplayAlerts = False '' ファイルに保存 lo_xlBook.SaveAs(as_file_name, Excel.XlFileFormat.xlWorkbookNormal) ''元に戻す lo_xlApp.DisplayAlerts = True finallyにて以下処理 Call lsub_ComObject_relese(lo_PageSetup) '' PageSetup の解放 Call lsub_ComObject_relese(lo_xlSheet) '' Sheet の解放 Call lsub_ComObject_relese(lo_xlSheets) '' Sheets の解放 lo_xlBook.Close(False) '' Book を閉じる Call lsub_ComObject_relese(lo_xlBook) '' Book の解放 Call lsub_ComObject_relese(lo_xlBooks) '' Books の解放 lo_xlApp.Quit() '' Excelを閉じる Call lsub_ComObject_relese(lo_xlApp) '' App を解放 GC.Collect() '' ガーベジコレクト起動 '' ComObjectの解放は以下処理を実施 Public Sub lsub_ComObject_relese(ByRef ComObject As Object) Try '' 提供されたランタイム呼び出し可能ラッパーの参照カウントをデクリメントする System.Runtime.InteropServices.Marshal.ReleaseComObject(ComObject) Catch ex As Exception Throw ex Finally '参照を解除する ComObject = Nothing End Try End Sub | ||||||||
|
投稿日時: 2008-09-29 18:39
ソースを見る限りはたまたまだと思いますけどね。 いずれにせよこのままでは再現できないと思います (略されている箇所が気になりますが)。 _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||
|
投稿日時: 2008-09-29 19:21
じゃんぬねっとさん!
お返事ありがとうございます。 再現ソースを取り急ぎ作成してみました。 何かお気づきの点ありましたらご教授ください。 ※ソース汚くてごめんなさい。 [ソース] [ソース] ''==================================== '' 変数宣言 ''==================================== '' エクセル関連 Dim lo_xlApp As Excel.Application = Nothing Dim lo_xlBooks As Excel.Workbooks = Nothing Dim lo_xlBook As Excel.Workbook = Nothing Dim lo_xlSheets As Excel.Sheets = Nothing Dim lo_xlSheet As Excel.Worksheet = Nothing Dim lo_PageSetup As Object = Nothing Dim lo_range As Excel.Range = Nothing Dim lo_xlBorders As Excel.Border = Nothing Dim lo_cells As Object = Nothing Dim lo_font As Object = Nothing '' 日付関連 Dim ls_start_date As String = "" Dim ls_end_date As String = "" Dim lio_culture As CultureInfo = New CultureInfo("ja-JP", True) lio_culture.DateTimeFormat.Calendar = New JapaneseCalendar() '' SQL関連 Dim ls_SQL As String = "" '' SQL Dim lo_DataTable As DataTable = Nothing '' SQLの戻り値 Dim li_SqlCount As Integer = 0 '' SQLの実行件数 '' その他 Dim ls_tax As String = "" '' 以下で a1 〜 a40 を宣言 Dim a1 As String = "" 略 Dim a40 As String = "" ''==================================== '' 起動処理 ''==================================== '' Excelインスタンス化 lo_xlApp = New Excel.Application '' ワークブックを設定 lo_xlBooks = lo_xlApp.Workbooks '' ブックを追加 lo_xlBook = lo_xlBooks.Add '' ワークシートを追加 lo_xlSheets = lo_xlBook.Worksheets '' ワークシートを設定 lo_xlSheet = lo_xlSheets.Item(1) ''-------------- '' ページ設定 ''-------------- lo_PageSetup = lo_xlSheet.PageSetup With lo_PageSetup .Orientation = ex_xlLandscape .ZOOM = 75 .LeftMargin = 0 .RightMargin = 0 End With ''-------------- '' 内容記載 ''-------------- '' テスト用のメソッドを、ある程度の回数コール '' ここでは例えば500回くらいコールしてみる Call sub_set_test(lo_xlSheet.Range("A3:J3"), "test") 略 Call sub_set_test(lo_xlSheet.Range("A3:J3"), "test") ''==================================== '' 保存処理 ''==================================== '' 保存時の問合せのダイアログを非表示に設定 lo_xlApp.DisplayAlerts = False '' ファイルに保存 lo_xlBook.SaveAs(as_file_name, Excel.XlFileFormat.xlWorkbookNormal) ''元に戻す lo_xlApp.DisplayAlerts = True finallyにて以下処理 Call lsub_ComObject_relese(lo_PageSetup) '' PageSetup の解放 Call lsub_ComObject_relese(lo_xlSheet) '' Sheet の解放 Call lsub_ComObject_relese(lo_xlSheets) '' Sheets の解放 lo_xlBook.Close(False) '' Book を閉じる Call lsub_ComObject_relese(lo_xlBook) '' Book の解放 Call lsub_ComObject_relese(lo_xlBooks) '' Books の解放 lo_xlApp.Quit() '' Excelを閉じる Call lsub_ComObject_relese(lo_xlApp) '' App を解放 GC.Collect() '' ガーベジコレクト起動 ''内容記載用のメソッド Public Sub gsub_set_test(ByRef ao_range As Excel.Range, ByVal as_str As String) '-------------- '' 内部変数宣言 '-------------- Dim lo_range As Excel.Range = Nothing Try lo_range = ao_range With lo_range lo_range.FormulaR1C1 = as_str End With Catch ex As Exception Throw ex Finally Call lsub_ComObject_relese(ao_range) Call lsub_ComObject_relese(lo_range) End Try End Sub '' ComObjectの解放は以下処理を実施 Public Sub lsub_ComObject_relese(ByRef ComObject As Object) Try '' 提供されたランタイム呼び出し可能ラッパーの参照カウントをデクリメントする System.Runtime.InteropServices.Marshal.ReleaseComObject(ComObject) Catch ex As Exception Throw ex Finally '参照を解除する ComObject = Nothing End Try End Sub | ||||||||
|
投稿日時: 2008-09-30 10:28
おそらく参照渡しにしているから呼び出し先で ReleaseComObject メソッドでデクリメントしてやれば良いと考えているかと思いますが、ここは呼び出し元でキッチリ参照の面倒を見てください。 これで解決しないようであれば、この部分をコメントアウトしてみてください。 Worksheet.Range はオーバーロードによっては余計な参照がカウントされる恐れがあります (遅延バインディングだと 100%)。
これは原因がわかりにくくなるだけなので外してください。 GC.Collect メソッドはコストも高いです。 これだけでは解決しないかもしれません。 ゆうさんは "空の変数 (文字型) を追加 (※1) した" もしくは "その変数を削除した" という切り分けをなさっていますが、それ以外の切り分けも積極的に試した方が解決が早いと思います。 たとえば PageSetup の記述をコメントアウトしても再現するか、再現しないかで別の原因が浮き彫りになることがあります。 _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||
|
投稿日時: 2008-10-01 15:16
じゃんぬねっとさん。
お世話になります。 お返事遅れてしまい申し訳ありません。 色々と試しているのですが、どうしてもプロセスが残ってしまします。。。 PageSetup の記述を書き直し、一旦はOKだったのですが、 同じ構文しか書いていないのに、量が増えてくるとプロセスが残って しまいます。 きっと私の記載が悪いと思うのですが。。 --ここは呼び出し元でキッチリ参照の面倒を見てください。 というと、 呼び出し元で変数に入れ、デクリメントする。 といった形でしょうか? Dim lo_ange as Excel.Range lo_range = lo_xlSheet.Range("A3:J3") Call sub_set_test(lo_range, "test") Call lsub_ComObject_relese(lo_range) | ||||||||
|
投稿日時: 2008-10-01 15:31
どこかで参照カウントが残っているのが原因でしょうから、ReleaseComObject メソッドの戻り値の確認も行ってください。
そうです。 Excel.Range は意図しない参照のカウントアップをすることがありますので特に注意してください。 _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||
|
投稿日時: 2008-10-01 19:47
じゃんぬねっとさん。
お世話になります。 色々細かくチェックしたところ、やはり暗黙宣言の部分がありました。 あるタイミングでは未発生だった為、見落としていたようです。。。 アドバイス等々ありがとうございました! |
1