tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルExcel ComObjectの解放
記事No11341
投稿日: 2014/10/28(Tue) 19:01
投稿者tera
環境:VB2010,Excel2010,Windows7 32bit

VB2010でExcelファイル内にある
グラフ目盛りの書き換えを行っています。

プログラムは完成し動作も問題ないのですが
COMオブジェクトが解放されません。

Dim xlSheet_g As Excel.Worksheet
Dim xlCharts As Excel.ChartObjects
Dim xlChart As Excel.ChartObject
Dim xlChart1 As Excel.Chart

xlSheet_g = DirectCast(xlSheets("グラフ"), Excel.Worksheet)
xlCharts = DirectCast(xlSheet_g.ChartObjects, Excel.ChartObjects)
xlChart = DirectCast(xlCharts(0), Excel.ChartObject)   '-------@
xlChart1 = xlChart.Chart

With xlChart1
    '目盛りの設定
    Dim xlAxes As Excel.Axes
    Dim xlAxis As Excel.Axis
    xlAxes = DirectCast(xlChart1.Axes, Excel.Axes)
    xlAxis = xlAxes.Item(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlSecondary)

    With xlAxis
        '目盛りの最大値
        .MaximumScale = 65
    End With
    MRComObject(xlAxis)
    MRComObject(xlAxes)
End With

MRComObject(xlChart1)
MRComObject(xlChart)
MRComObject(xlCharts)
MRComObject(xlSheet_g)

プログラムをコメントにしていき、@の部分で何か解放忘れを
しているのではないかと思っています。

何を解放し忘れているのでしょうか?
よろしくお願いします。

[ツリー表示へ]
タイトルRe: Excel ComObjectの解放
記事No11342
投稿日: 2014/10/28(Tue) 21:23
投稿者魔界の仮面弁士
> 何を解放し忘れているのでしょうか?

念のため、ReleaseComObject の戻り値を確認してみて下さい。
それらすべてが 0 を返していますか?

もしも 1 以上を返してくるケースがあった場合は、そのオブジェクトに対して
複数の参照カウントが生成されていますので、0 になるまで ReleaseComObject を
繰り返すか、もしくは、FinalReleaseObject で処理することになります。

(なお、0 未満の値を返してきている場合は 過解放です)


> xlSheet_g = DirectCast(xlSheets("グラフ"), Excel.Worksheet)
この xlSheets に関する解説が無いようですが、xlSheets が原因というわけではないのですね?


> xlChart = DirectCast(xlCharts(0), Excel.ChartObject)
これは
 xlChart = DirectCast(xlCharts.Item(1), Excel.ChartObject)
だとどうでしょう。

参照設定しているライブラリによっては、ChartObjects に既定のインデクサが無い場合があるためです。
また、Excel のコレクションオブジェクトは、基本的には 1 からカウントするはず…。

[ツリー表示へ]
タイトルRe^2: Excel ComObjectの解放
記事No11343
投稿日: 2014/10/29(Wed) 12:06
投稿者tera
> > 何を解放し忘れているのでしょうか?
>
> 念のため、ReleaseComObject の戻り値を確認してみて下さい。
> それらすべてが 0 を返していますか?
>
> もしも 1 以上を返してくるケースがあった場合は、そのオブジェクトに対して
> 複数の参照カウントが生成されていますので、0 になるまで ReleaseComObject を
> 繰り返すか、もしくは、FinalReleaseObject で処理することになります。
>
> (なお、0 未満の値を返してきている場合は 過解放です)
>
>
> > xlSheet_g = DirectCast(xlSheets("グラフ"), Excel.Worksheet)
> この xlSheets に関する解説が無いようですが、xlSheets が原因というわけではないのですね?
>
ReleaseComObject で戻り値を確認してみたところ
xlSheetsの後ろで戻り値が1になっていました。

'確認用
Dim xlSheet_g As Excel.Worksheet
xlSheet_g = DirectCast(xlSheets("グラフ"), Excel.Worksheet)
cnt = System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet_g)

xlSheetsは下のxlSheetsを使用しています。
xlSheetsの解放はExcelCloseのところで行っているのでは足りないということだと思いますが
何を解放していないのかわからないです。


Private Sub ExcelOpen(ByVal FilePath As String, ByVal SheetName As String)
        'Excel のオープン処理用プロシージャ
        xlClose = False   '起動中は、ユーザが Excel を閉じれないように
        xlApp = New Excel.Application
        'Excel の WorkbookBeforeClose イベントを取得
        AddHandler xlApp.WorkbookBeforeClose, AddressOf xlApp_WorkbookBeforeClose

        xlBooks = xlApp.Workbooks
        If FilePath.Length = 0 Then
            '新規のファイルを開く場合
            xlBook = xlBooks.Add
            xlSheets = xlBook.Worksheets
            xlSheet = DirectCast(xlSheets.Item(1), Excel.Worksheet)
        Else
            '既存のファイルを開く場合
            xlBook = xlBooks.Open(FilePath)
            xlSheets = xlBook.Worksheets
            xlSheet = DirectCast(xlSheets(SheetName), Excel.Worksheet)
        End If
        xlApp.Visible = True
    End Sub


>
> > xlChart = DirectCast(xlCharts(0), Excel.ChartObject)
> これは
>  xlChart = DirectCast(xlCharts.Item(1), Excel.ChartObject)
> だとどうでしょう。
変更してみたところ
COMException' のハンドルされていない例外が mscorlib.dll で発生しました
HRESULT からの例外:0x800A03EC
となりました。

>
> 参照設定しているライブラリによっては、ChartObjects に既定のインデクサが無い場合があるためです。
> また、Excel のコレクションオブジェクトは、基本的には 1 からカウントするはず…。
解放忘れを除けばグラフの最大値も変更されてますし
動きにおかしなところはなさそうです。
参照設定しているライブラリは
Excel 14.0 Object Library
Office 14.0 Object Library です。

[ツリー表示へ]
タイトルRe^3: Excel ComObjectの解放
記事No11344
投稿日: 2014/10/29(Wed) 14:28
投稿者魔界の仮面弁士
> xlSheetsの解放はExcelCloseのところで行っているのでは足りないということだと思いますが

掲示板に書かれていない、省略された部分に原因があるのかも知れません。


原因の切り分けのため、第三者がそのまま検証できるよう、
必要な変数宣言もすべて含めた、完全なソースコードを省略せずに
記載していただけないでしょうか。検証に必要最低限の内容で。

特定の Excel 文書ファイルが必要なら、その文書の作成手順もあると助かります。


もしも他者が「実験コード」でも現象を再現できるようであれば、
原因を追跡しやすくなりますし、他の人には再現できないようであれば、
プログラムではなく、動作環境に問題がある可能性が浮上してきます。

また、実験用に作り直したコードでは再現しないということになれば、
今度は既存コードとの違いを調べていくという作業を行えばよい事になりますよね。



> 何を解放していないのかわからないです。

http://hanatyan.sakura.ne.jp/dotnet/Excel01.htm で紹介されている
MRComObject の実装を呼び出しているだとしたら、
「MRComObject(xlSheets)」としている箇所を
「MRComObject(xlSheets, True)」に変更してみて下さい。

それで解放漏れが無くなるようであれば、どこかで xlSheets への
COM 参照が複数生成されてしまっていることになります。
どの行を追加した段階で、参照カウントが増加してしまっているのかを追跡してみてください。

このとき、念のため「Option Strict On」にてコンパイルが通るようにしておきましょう。
暗黙の型変換が原因で、参照カウントが増じてしまうケースもあるようなので。

[ツリー表示へ]
タイトルRe^3: Excel ComObjectの解放
記事No11345
投稿日: 2014/10/31(Fri) 10:10
投稿者花ちゃん
> > > xlChart = DirectCast(xlCharts(0), Excel.ChartObject)
> > これは
> >  xlChart = DirectCast(xlCharts.Item(1), Excel.ChartObject)
> > だとどうでしょう。
> 変更してみたところ
> COMException' のハンドルされていない例外が mscorlib.dll で発生しました
> HRESULT からの例外:0x800A03EC
> となりました。

横から失礼します。
このグラフは、Sheet1(xlSheets("グラフ")) とかの上に書かれているグラフでしょうか?
それとも、 Graph1 とかの グラフ用のシート上に書かれているグラフでしょうか?
xlSheets("グラフ") 上に書かれているグラフなら
xlSheet_g = DirectCast(xlSheets("グラフ"), Excel.Worksheet)
xlCharts = DirectCast(xlSheet_g.ChartObjects, Excel.ChartObjects)
xlChart = DirectCast(xlCharts.Item(1), Excel.ChartObject)   '-------@
xlChart1 = xlChart.Chart
でエラーもなくプロセスも解放されました。

但し、私の環境では、xlSheets("Sheet1") に変更し、XlAxisGroup.xlPrimary で試した結果ですが。
その他は、投稿されたコードを使って、起動・終了は、ここのサイトに掲載のコードを使って試して見ました。
(Excel 2013 /Sheet1上に書かれたグラフを使って、)

xlChart = DirectCast(xlCharts.Item(1), Excel.ChartObject) でエラーがでるのなら、既存のグラフが
参照できていない等が原因かと
xlChart = DirectCast(xlCharts(0), Excel.ChartObject) で試すとエラーはでませんがプロセスが残りました。

グラフの表示・修正部分のコードをコメントにした場合は、プロセスは解放されているのですよね?

[ツリー表示へ]