エクセル操作にて改ページとヘッダーへの値セットの際にプロセスの終了を行うには?

解決


ミキミニ  2005-12-08 07:17:25  No: 128674

現在VB.NETにて、エクセルにDBの値を帳票として吐き出す処理を行っています。
その際のエクセルのプロセスが残る問題にて行き詰っております。

こちらの掲示板の過去ログや、紹介されておりました
花ちゃんさんのサイトを拝見し、ほぼ解放の処理を終えることができたのですが、
エクセルのヘッダーへの値のセットと、
改ページを行う処理についてプロセスが残ったままになっています。

'ヘッダーへ値セット
xlSheet.PageSetup.CenterHeader = "シート名"  ①
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet)
xlSheet = Nothing

'改ページの挿入
xlRange = xlSheet.Range("H" & CStr(lngRpCnt + 41))  xlSheet.HPageBreaks.Add(before:=xlRange)  ②
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlRange)
xlRange = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet)
xlSheet = Nothing

ヘッダーへの値のセットではxlSheetの解放、
改ページの挿入ではxlSheet、xlRangeの解放をそれぞれ行っていますが
この他に解放しなければならないものがあるのでしょうか?
①②それぞれ1行をコメントにすると、プロセスは終了しています。

どのようにすればプロセスを終了させることができるのでしょうか?
ご教授お願い致します。


魔界の仮面弁士  2005-12-08 08:47:01  No: 128675

基本的に、『.』を連続して使うのは赤信号だと思ってください。

(1) の方は、PageSetupオブジェクトの参照が解放されていませんし、
(2) の方は、HPageBreaksコレクションの参照が解放されていません。

それぞれを変数に受けてから、ReleaseComObject を呼び出しましょう。


ミキミニ  2005-12-08 18:19:52  No: 128676

魔界の仮面弁士さん、ご回答ありがとうございます。

>それぞれを変数に受けてから、ReleaseComObject を呼び出しましょう。
過去ログの魔界の仮面弁士さんの書き込みにあったのですが、
.Cells が返す物は、Rangeオブジェクトなので、
CellsだけでなくRangeの解放が必要なように、
PageSetupオブジェクトとHPageBreaksコレクションも何か
オブジェクトを返しているのに、それを解放していないという
ことでよいのでしょうか?

色々自分なりに調べたつもりですが、
各オブジェクトとコレクションを最終的にどの変数に受けて
どの参照を解放してやればよいかが分かりません。
ご教授いただけないでしょうか?


ななし  2005-12-08 19:48:03  No: 128677

>ご教授いただけないでしょうか?

久々に、正しい使い方を見ました。


魔界の仮面弁士  2005-12-08 19:48:26  No: 128678

>> (2) の方は、HPageBreaksコレクションの参照が解放されていません。
さらに(2)の方は、HPageBreakオブジェクトの参照も解放されていませんね。

>> 基本的に、『.』を連続して使うのは赤信号だと思ってください。

これはたとえば、Excelのオブジェクトで、
  hoge.hage.hige()   '『.』が2回連続して使われている!!
というようなメソッド呼び出しがあったとしたら、
  A = hoge.hage  'hageオブジェクトを変数Aに受け取る
  A.hige()   'hageクラスのhigeメソッドを呼び出す
  Marshal.ReleaseComObject(A)   'hageオブジェクトを解放
  Marshal.ReleaseComObject(hoge)  'hogeオブジェクトを解放
のように書く必要がある、という事になります。
メソッドの呼び出しだけでなく、プロパティ操作も同様です。

また、その hige メソッドが、別のCOMオブジェクトを返す場合には、
  A = hoge.hage
  B = A.hige()
  Marshal.ReleaseComObject(B)
  Marshal.ReleaseComObject(A)
  Marshal.ReleaseComObject(hoge)
のように、戻り値の解放処理も必要となります。

もう少し具体的に書くと、
  xlSheet.PageSetup.CenterHeader = 〜
のようなプロパティ操作の場合は、
  A = xlSheet.PageSetup  'PageSetupオブジェクトを受け取る
  A.CenterHeader = 〜
  Marshal.ReleaseComObject(A)
というイメージになりますし、
  xlSheet.HPageBreaks.Add(before:=xlRange)
の方に関しては、
  B = xlSheet.HPageBreaks    'HPageBreaksコレクションを受け取る
  C = B.Add(before:=xlRange) 'HPageBreakオブジェクトを受け取る
  Marshal.ReleaseComObject(C)
  Marshal.ReleaseComObject(B)
のようになる、という事ですね。

> 過去ログの魔界の仮面弁士さんの書き込みにあったのですが、
どれの事でしょう?


ミキミニ  2005-12-08 20:05:09  No: 128679

魔界の仮面弁士さん、大変ご丁寧な回答ありがとうございます。
細かくご指摘頂き、行わなければいけない事が把握できました。

ただ、もう少しお付き合い頂きたいのですが、
>A = xlSheet.PageSetup  'PageSetupオブジェクトを受け取る
という部分のAというのは、
Dim A As Object で宣言するのでしょうか?
それともDim A As Excel.〜で宣言すべきなのでしょうか?
xlSheet等はDim xlSheet As Excel.Worksheetと宣言しています。

こちらも魔界の仮面弁士さんの過去ログを拝見すると、
厳密な型付け(As Excel.〜) と、そうでないもの(As System.Object)が
混じってしまうのは良くないと書かれておられました。

同様に、
>B = xlSheet.HPageBreaks    'HPageBreaksコレクションを受け取る
>C = B.Add(before:=xlRange) 'HPageBreakオブジェクトを受け取る
についても、具体的にはどの型で受け取ればよいのか
ご教授いただけませんでしょうか?

参考にさせていただいた魔界の仮面弁士さんの過去ログは
下記のページの書き込みです。
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200412/04120059.txt


ミキミニ  2005-12-08 20:35:29  No: 128680

ご指摘頂いた部分を改善して、ヘッダーの方は
とりあえずDim objheader As Objectで宣言の後解放してやると
うまくプロセスが終了致しました。

'ヘッダーへの値のセット
Dim objheader As Object
objheader = xlSheet.PageSetup
objheader.CenterHeader = "シート名"

System.Runtime.InteropServices.Marshal.ReleaseComObject(objheader)
objheader = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet)
xlSheet = Nothing

ただ、改ページの方なのですが、書かれていたことをそのまま実行してみようと
CollectionとObjectで宣言を行い、記入したところ、
下記★の部分で青い波線が引かれ、エラーになってしまいました。
やはり宣言に問題があるのでしょうか。。

'改ページの挿入
Dim B As Collection
Dim C As Object

xlRange = xlSheet.Range("H" & CStr(lngRpCnt + 41))
B = xlSheet.HPageBreaks    'HPageBreaksコレクションを受け取る
★C = B.Add(before:=xlRange)  'HPageBreakオブジェクトを受け取る


魔界の仮面弁士  2005-12-09 03:42:14  No: 128681

> Dim B As Collection
これは使えません。

Excel 固有のコレクション型と、.NET の Collection クラスとの間には
互換性がありませんので、この場合は単なる Object 型を使ってください。

もしも厳密な型を利用したいのであれば、
Microsoft.Office.Interop.Excel.HPageBreaks インターフェイス型です。
# Excel PIA (microsoft.office.interop.excel.dll)を参照設定している場合


ミキミニ  2005-12-09 05:27:14  No: 128682

魔界の仮面弁士さんの仰るとおり、Object型で宣言し、
全て解放処理を行ったのですが、まだプロセスが残ります。
下記★の行をコメントにするとプロセスは終了します。

解放の順番がおかしいのかもと思い色々試しましたが違うようですし、
B.Add(before:=xlRange)を更にオブジェクトに入れるのかと
試してみましたがうまく行きません。。

どこに問題があるのか、正直お手上げ状態になってしまったのですが
何かまだ解放されていないオブジェクトがあるのでしょうか?

'改ページの挿入
Dim B As Object
Dim C As Object
                        
B = xlSheet.HPageBreaks    'HPageBreaksコレクションを受け取る
xlRange = xlSheet.Range("H" & CStr(lngRpCnt + 41))
★C = B.Add(before:=xlRange) 'HPageBreakオブジェクトを受け取る

pbsMRComObject(C)
pbsMRComObject(B)
pbsMRComObject(xlRange)
pbsMRComObject(xlSheet)


魔界の仮面弁士  2005-12-09 08:04:05  No: 128683

Excel 2003 のレイトバインドで試してみました……なるほど、残りますね。

とりあえず、Worksheet.HPageBreaks の代わりに、Range.PageBreak を
用いれば残らないようです。回避策として試してみてください。

======= 問題のコード(原因調査中) =======
 Dim X As Object= CreateObject("Excel.Application")
 X.Visible = True
 Dim Bs As Object = X.Workbooks
 Dim B As Object = Bs.Add()
 Dim Ss As Object = B.Worksheets
 Dim S As Object = Ss(1)
 Dim Rs As Object = S.Rows
 Dim R As Object = Rs(3)

 '----> コメントを外すと残る!
 Dim Hs As Object = S.HPageBreaks
 'Dim H As Object = Hs.Add(R)
 MessageBox.Show("改ページを挿入しました。")
 'Marshal.ReleaseComObject(H)
 Marshal.ReleaseComObject(Hs)
 '<----

 Marshal.ReleaseComObject(Hs)
 Marshal.ReleaseComObject(R)
 Marshal.ReleaseComObject(Rs)
 Marshal.ReleaseComObject(S)
 Marshal.ReleaseComObject(Ss)
 B.Close(False)
 Marshal.ReleaseComObject(B)
 Marshal.ReleaseComObject(Bs)
 X.Quit()
 Marshal.ReleaseComObject(X)
 MessageBox.Show("プロセスは残っていますか?")

======= 残らないコード =======
 Dim X As Object = CreateObject("Excel.Application")
 X.Visible = True
 Dim Bs As Object = X.Workbooks
 Dim B As Object = Bs.Add()
 Dim Ss As Object = B.Worksheets
 Dim S As Object = Ss(1)
 Dim Rs As Object = S.Rows
 Dim R As Object = Rs(3)

 '----> これなら残らない
 R.PageBreak = -4135  'Trueを代入してもOK
 MessageBox.Show("改ページを挿入しました。")
 '<----

 Marshal.ReleaseComObject(R)
 Marshal.ReleaseComObject(Rs)
 Marshal.ReleaseComObject(S)
 Marshal.ReleaseComObject(Ss)
 B.Close(False)
 Marshal.ReleaseComObject(B)
 Marshal.ReleaseComObject(Bs)
 X.Quit()
 Marshal.ReleaseComObject(X)
 MessageBox.Show("プロセスは残っていますか?")


魔界の仮面弁士  2005-12-09 08:18:51  No: 128684

レイトバインドではなく、厳密な型(Excel PIA)を用いた場合には
HPageBreaks.Add しても、プロセスは残らないようです。

Dim X As Excel.Application = DirectCast(CreateObject("Excel.Application"), Excel.Application)
X.Visible = True
Dim Bs As Excel.Workbooks = X.Workbooks
Dim B As Excel.Workbook = Bs.Add()
Dim Ss As Excel.Sheets = DirectCast(B.Worksheets, Excel.Sheets)
Dim S As Excel.Worksheet = DirectCast(Ss(1), Excel.Worksheet)
Dim Rs As Excel.Range = S.Rows
Dim R As Excel.Range = DirectCast(Rs(3), Excel.Range)

'----> どちらの方法でも残らない
'R.PageBreak = Excel.XlPageBreak.xlPageBreakManual
'MessageBox.Show("改ページを挿入しました。")
'----
Dim Hs As Excel.HPageBreaks = S.HPageBreaks
Dim H As Excel.HPageBreak = Hs.Add(R)
MessageBox.Show("改ページを挿入しました。")
Marshal.ReleaseComObject(H)
Marshal.ReleaseComObject(Hs)
'<----

Marshal.ReleaseComObject(R)
Marshal.ReleaseComObject(Rs)
Marshal.ReleaseComObject(S)
Marshal.ReleaseComObject(Ss)
B.Close(False)
Marshal.ReleaseComObject(B)
Marshal.ReleaseComObject(Bs)
X.Quit()
Marshal.ReleaseComObject(X)
MessageBox.Show("プロセスは残っていますか?")


ミキミニ  2005-12-09 19:38:05  No: 128685

Range.PageBreakを用い、魔界の仮面弁士さんに書いていただいたコードを
利用してソースを修正し、無事プロセスを終了させることができました。

魔界の仮面弁士さん、長らくお付き合い頂き、
非常に丁寧かつ分かりやすい解説、大変勉強になりました。
また、今回の質問の件以外にも、過去の魔界の仮面弁士さんの書き込みを
非常に多く活用させていただきました。
この場をお借りしてお礼申し上げます。
本当にありがとうございました。


魔界の仮面弁士  2005-12-22 11:29:19  No: 128686

> ======= 問題のコード(原因調査中) =======

ようやく分かりました。

どうやら、レイトバインドの場合、
 Dim Hs As Object = S.HPageBreaks
 Dim H As Object = Hs.Add(R)
の処理を行った時点で、変数 R の参照カウントが
増加してしまっていたようです。


※返信する前に利用規約をご確認ください。




  


  このエントリーをはてなブックマークに追加