tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトル再び Excelのプロセスが残る問題
記事No1499
投稿日: 2005/03/23(Wed) 17:57
投稿者匿名
[OSのVer]:WindowsXp    [VBのVer]:VB.NET2003

再度、Excelのプロセスが残る問題で悩んでいます。

新規プロジェクトを立ち上げ、フォームにボタンを1つ貼り、
魔界の仮面弁士さん(No1490)に教えてもらったソースをコピペすると
処理が終わったときにExcelのリソースは残っていません。
PIA は設定してあります。 が、問題は以下のソースです。

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

        Dim Ex2003 As Microsoft.Office.Interop.Excel.Application
        Dim Books As Microsoft.Office.Interop.Excel.Workbooks
        Dim Book As Microsoft.Office.Interop.Excel.Workbook
        Dim Sheets As Microsoft.Office.Interop.Excel.Sheets
        Dim Sheet As Microsoft.Office.Interop.Excel.Worksheet
        Dim R1, R2, R3, R4 As Microsoft.Office.Interop.Excel.Range
        Dim intRow As Integer
        Dim intCol As Integer

        Ex2003 = New Microsoft.Office.Interop.Excel.ApplicationClass
        Ex2003.Visible = False
        Ex2003.DisplayAlerts = False

        Books = Ex2003.Workbooks
        Book = Books.Add()
        Sheets = Book.Worksheets
        Sheet = DirectCast(Sheets(1), Microsoft.Office.Interop.Excel.Worksheet)
        R1 = Sheet.Cells

        'タイトル1
        R2 = DirectCast(R1(1, 1), Microsoft.Office.Interop.Excel.Range)
        R3 = DirectCast(R1(1, 3), Microsoft.Office.Interop.Excel.Range)
        R4 = Sheet.Range(R2, R3)
        R4.Merge()
        R4.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter
        R4.Value = "タイトル1"

        'タイトル2
        R2 = DirectCast(R1(1, 4), Microsoft.Office.Interop.Excel.Range)
        R3 = DirectCast(R1(1, 6), Microsoft.Office.Interop.Excel.Range)
        R4 = Sheet.Range(R2, R3)
        R4.Merge()
        R4.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter
        R4.Value = "タイトル2"

        MsgBox("終了")

        System.Runtime.InteropServices.Marshal.ReleaseComObject(R4)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(R3)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(R2)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(R1)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(Sheet)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(Sheets)

        Book.SaveAs("C:\Documents and Settings\miyakeha\デスクトップ\Test.xls")
        Book.Close()

        System.Runtime.InteropServices.Marshal.ReleaseComObject(Book)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(Books)

        Ex2003.Quit()

        System.Runtime.InteropServices.Marshal.ReleaseComObject(Ex2003)

    End Sub

タイトル2の書き込み部分をコメントアウトすると「終了」のメッセージボックスで
OKを押した瞬間にExcelはタスクマネージャから消えるのですが、
タイトル2の書き込みも処理を行うとフォームを閉じるタイミングでタスクマネージャから
消えるようになります。 これは何が影響しているのでしょうか?

現在、自分の方のソースではタイトルを書き込んだ後、それに続いて明細(250行、20列ほど)を
1セルづつ書き込んでいるのですがExcelのリソースが残ってしまいます。
処理に時間がかかる為、ループの場所でプログレスバーを操作しているのですが
バーの操作部分(DoEvents含む)をコメントアウトするとExcelが残らなくなったりします。
状況を再現させれる簡単なソースは、これから用意させて頂きますが
まずはタイトル1のみの書き込みとタイトル2までの書き込みで何が違うのか
解決できない為、質問させて頂きました。
変数を、それぞれ分けてみたり、都度、初期化してみたり試行錯誤したのですが
動作が安定しないというか、法則が見出せない状況で困っております。

[ツリー表示へ]
タイトルRe: 再び Excelのプロセスが残る問題
記事No1500
投稿日: 2005/03/23(Wed) 18:53
投稿者魔界の仮面弁士
> まずはタイトル1のみの書き込みとタイトル2までの書き込みで何が違うのか
> 解決できない為、質問させて頂きました。

例によって、COMオブジェクトの解放を行っていないためです。(^_^;)

《タイトル2》部で参照した R2, R3, R4 は ReleaseComObject してありますが、
《タイトル1》部で参照した R2, R3, R4 は ReleaseComObject していませんよね。

[ツリー表示へ]
タイトルRe^2: 再び Excelのプロセスが残る問題
記事No1501
投稿日: 2005/03/23(Wed) 19:10
投稿者匿名
早速のレス有難う御座います。 本当に助かります。

'タイトル1
R2 = DirectCast(R1(1, 1), Microsoft.Office.Interop.Excel.Range)
R3 = DirectCast(R1(1, 3), Microsoft.Office.Interop.Excel.Range)
R4 = Sheet.Range(R2, R3)
R4.Merge()
R4.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter
R4.Value = "タイトル1"
System.Runtime.InteropServices.Marshal.ReleaseComObject(CType(R4, Object))
System.Runtime.InteropServices.Marshal.ReleaseComObject(CType(R3, Object))
System.Runtime.InteropServices.Marshal.ReleaseComObject(CType(R2, Object))

'タイトル2
R2 = DirectCast(R1(1, 4), Microsoft.Office.Interop.Excel.Range)
R3 = DirectCast(R1(1, 6), Microsoft.Office.Interop.Excel.Range)
R4 = Sheet.Range(R2, R3)
R4.Merge()
R4.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter
R4.Value = "タイトル2"
System.Runtime.InteropServices.Marshal.ReleaseComObject(CType(R4, Object))
System.Runtime.InteropServices.Marshal.ReleaseComObject(CType(R3, Object))
System.Runtime.InteropServices.Marshal.ReleaseComObject(CType(R2, Object))

の繰り返しで、タイトル3、4と使っていけば良いという事なのですよね。

タイトル部を、その点に注意して明細部を見直してみます。
自分のソースを元にサンプルソースを作るとリソース残りが再現しないのです。

1行目のタイトル1〜4はセルを結合して出力し、
2行目は1セルに1項目づつタイトルを設定し
3行目以下、明細をループで回しています。

プログレスバーをコメントで消すとリソースが残らなかったり、
1行目のタイトル4のみを消すとリソースが残らなかったり
意味のわからない状況になっております。

管理人様>
どれぐらい長いソースまでアップしてしまってよいのでしょうか?

[ツリー表示へ]
タイトルRe: 再び Excelのプロセスが残る問題
記事No1503
投稿日: 2005/03/24(Thu) 11:48
投稿者匿名
Dim Ex2003 As Microsoft.Office.Interop.Excel.Application は
Applicationで定義してますが

Ex2003 = New Microsoft.Office.Interop.Excel.ApplicationClass って Newしてますよね。
これは、タイプミスではなくて敢えて、この処理にしているのでしょうか?

WorkBooks Workbook と来ると WorkSheets WorkSheet としてしまいそうですが
Sheets Worksheet になっていますよね
この部分は WorkSheetsに置き換えてみたらエラーが発生しました。

[ツリー表示へ]
タイトルRe^2: 再び Excelのプロセスが残る問題
記事No1504
投稿日: 2005/03/24(Thu) 12:08
投稿者魔界の仮面弁士
> Dim Ex2003 As Microsoft.Office.Interop.Excel.Application は
> Applicationで定義してますが
> Ex2003 = New Microsoft.Office.Interop.Excel.ApplicationClass って Newしてますよね。
> これは、タイプミスではなくて敢えて、この処理にしているのでしょうか?

あえてそうしています。
ClassをNewするなら分かりますが、InterfaceをNewするのは変ですしね。

ApplicationClassの定義をVB的に書くなら、内部的には、

  Public Class ApplicationClass
    Implements _Application, Application, AppEvents_Event
        :
        :
  End Class

というイメージになっています。ちなみに、Application型の方は、

  Public Interface Application
      Implements _Application, AppEvents_Event
  End Interface

となっていますね。


> WorkBooks Workbook と来ると WorkSheets WorkSheet としてしまいそうですが
> Sheets Worksheet になっていますよね
> この部分は WorkSheetsに置き換えてみたらエラーが発生しました。
Worksheets型を返すプロパティ/メソッドは、私も知りません。(^^;
どういう時に使うものなんでしょうね。この型。

[ツリー表示へ]
タイトルEntireColumn.AutoFit
記事No1505
投稿日: 2005/03/24(Thu) 14:10
投稿者匿名
セルを結合して作成するヘッダー1行目
個々のセルに1項目づつ出力するヘッダー2行目
3行目以降の明細データ出力
プログレスバーの操作

全ての作業を終わらせてもリソースが残らない状態までいけました。

が、保存を行う前にセルの列幅を調整したいのです。
以下ソースです

'ここまでに R2、R3、R4 は解放済みです

R2 = DirectCast(R1(1, 1), Excel.Range)
R3 = DirectCast(R1(250, 25), Excel.Range)   '最大行・最大列です
R4 = Sheet.Range(R2, R4)
R4.EntireColumn.AutoFit()

System.Runtime.InteropServices.Marshal.ReleaseComObject(R4)
System.Runtime.InteropServices.Marshal.ReleaseComObject(R3)
System.Runtime.InteropServices.Marshal.ReleaseComObject(R2)

と、現在コーディングしているのですが、この部分が原因でリソースが残ります。

R1.EntireColumn.AutoFit()

と始めはコーディングしていたのですが、これも駄目でした。
R5、R6、R7 と新しく Excel.Range を作って AutoFit後に解放してもリソースは残ります。

リソースを残さずに列幅を調整させるには、どのような指定方法をすればよいでしょうか?

[ツリー表示へ]
タイトルRe: EntireColumn.AutoFit
記事No1506
投稿日: 2005/03/24(Thu) 15:01
投稿者魔界の仮面弁士
なんか、同じミスばかり繰り返していますね……(泣)


> R4 = Sheet.Range(R2, R4)
引数に指定した方の R4 の解放処理は?

> R4.EntireColumn.AutoFit()
R4.EntireColumn から返される Range オブジェクトの解放処理は?

[ツリー表示へ]
タイトルRe^2: EntireColumn.AutoFit
記事No1507
投稿日: 2005/03/24(Thu) 16:33
投稿者匿名
度々、回答頂きまして本当に申し訳ないです。

Dim R5 As Excel.Range                         '今回追加しました

R2 = DirectCast(R1(1, 1), Excel.Range)
R3 = DirectCast(R1(250, 25), Excel.Range)     '最大行・最大列です
R4 = Sheet.Range(R2, R3)                      'R3 が R4 になってたのは書き込みミスでした

R5 = DirectCast(R4.EntireColumn, Excel.Range)
R5.EntireColumn.AutoFit()

System.Runtime.InteropServices.Marshal.ReleaseComObject(R5)
System.Runtime.InteropServices.Marshal.ReleaseComObject(R4)
System.Runtime.InteropServices.Marshal.ReleaseComObject(R3)
System.Runtime.InteropServices.Marshal.ReleaseComObject(R2)

どうも自分は R2 〜 R5 を変数として考えていたのですけど、
まったく別物って考えたほうが良いってことなんですよね?
1回使う毎に解放するわけですし。

今回のバージョンで実行してもリソースが残ってしまいました。
AutoFitの部分をコメントアウトするとリソースは残りません。
すみませんが、もう少しアドバイス頂けないでしょうか。

[ツリー表示へ]
タイトルRe^3: EntireColumn.AutoFit
記事No1508
投稿日: 2005/03/24(Thu) 16:36
投稿者匿名
すみません。 リソース消えました。

R5 = DirectCast(R4.EntireColumn, Excel.Range)
R5.EntireColumn.AutoFit()



R5 = DirectCast(R4.EntireColumn, Excel.Range)
R5.AutoFit()

に修正したら上手くいきました。
いろいろアドバイス頂き本当に有難うございました。
今回の問題で、いろいろ勉強になりました。

[ツリー表示へ]
タイトル補足事項として
記事No1509
投稿日: 2005/03/24(Thu) 18:00
投稿者魔界の仮面弁士
> どうも自分は R2 〜 R5 を変数として考えていたのですけど、
> まったく別物って考えたほうが良いってことなんですよね?

いえいえ。それ自体はただの変数ですよ。(^^;


問題なのは、それらの変数に、Excel の ActiveXコンポーネントを
保持させているという点にあります。


厄介な事に、ActiveX(COM)のオブジェクト と .NET のオブジェクトでは、
メモリの管理方法が全く異なるため、.NET側の変数が使われなくなっても、
COM側のオブジェクトまでが「即座に」解放されるわけではありません。

それゆえ、.NETからCOMを利用する場合は、取得したCOMオブジェクトを
「自分で解放しなければいけない」という自体が発生するわけです。

hhttp://www.microsoft.com/japan/msdn/library/ja/jpdnbnetguide/htm/IntroDotNET_ch02-08.asp?



これは、Excel以外の COMオブジェクトを利用している場合にもいえますので、
.NET から COM を利用する場合は、ReleaseComObject を呼び忘れている
部分が無いか、常に意識しながらコーディングするようにして下さい。

Excel ならば、プロセスが残っている事を簡単に確認できますが、
その他のCOMオブジェクトの場合は、うっかり解放し忘れていても、
その事に、なかなか気づきにくかったりしますからね。

[ツリー表示へ]
タイトルRe: 補足事項として
記事No1511
投稿日: 2005/03/25(Fri) 09:46
投稿者匿名
ご親切に有難う御座います。
なんとなく分かってきた感じです。

変数 = 式   みたいなのでメモリが確保されると思っていたのですけど

今回は

rngCells.EntireColumn.AutoFit

この部分で解放されていないと指摘を頂き、ぴんと来ませんでした。

Dim rngTest As Excel.Range = rngCells.EntireColumn
rngTest.AutoFit()

こんな感じで動いているから rngTest の解放をしなさいよ って意味なのかな
と今は理解しています。

[ツリー表示へ]