tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトル Subroutineの引数が原因でExcelが開放できなくなります。
記事No9324
投稿日: 2009/08/31(Mon) 17:30
投稿者camputer
 こんにちは、質問させていただきます。camputerと申します。
10年近く研究で計算プログラムを作成しておりましたが、
1年ほど前にVB.NETに触れVBが好きになりました。
どうぞよろしくお願いいたします。
 開発環境はVB2008+XP+Excel2003になります。

 ↓のように、Subroutine呼び出しの行で解放できなくなるのですが、

Private Sub Excel練習
・・・
 Dim Shape1 As Excel.Shape
・・・
 subroutine1(String1, String2, Shape1, String3, Integer1, Integer2)
                                 '↑ここの行が無ければ開放されます。。
・・・
End Sub


Sub subroutine1(ByVal String1, ByVal String2, ByVal Shape1, ByVal String3 , ByRef Integer1, ByRef Integer2)

   '※Subroutine内のコード無し
End Sub


 テストしておりますと、上のsubroutine1の引数を(2行とも)変更して、
subroutine1(String1, String2, Shape1, String3, Integer1) 
だと開放できるので、Integer2が怪しいのかな?と考え、次のようにしてみましたが、
subroutine1(Integer2) 
何故か↑でも開放できます。。。

 解決手段が塞がってしまいました。。。何か思い当たることなど
是非ともヒントをいただけないでしょうか。
Excelの開放については散々出ているようなので、どこかに情報源があるのではと
思うのですが、「Subroutine 開放」などと検索しても分かりませんでした。
 もしもとんちんかんな質問でしたら申し訳ございませんが、
是非ともアドバイスをいただきたくお願いいたします。
どうぞよろしくお願いいたします。

[ツリー表示へ]
タイトルRe:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9325
投稿日: 2009/08/31(Mon) 18:51
投稿者魔界の仮面弁士
> Sub subroutine1(ByVal String1, ByVal String2, ByVal Shape1, ByVal String3 , ByRef Integer1, ByRef Integer2)

それぞれの引数に、As で正しい型を指定してください。

暗黙の型変換が発生すると、そこで参照カウントが増大してしまう可能性があるため、
解放処理が複雑化してしまいます。

[ツリー表示へ]
タイトルRe^2:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9327
投稿日: 2009/08/31(Mon) 20:23
投稿者camputer

 魔界の仮面弁士 様

 どうもありがとうございました!直せました!

??? 他のサブルーチンでは型宣言無しでうまく通っているものがほとんどだったので,
ここで解放が複雑化するとは考えておりませんでした.今から過去のコードを全部見直します.
今まではサブルーチンの量自体が少なく,解放を複雑化するに至っていなかったという事でしょうか...
 引数を減らすと症状が100%改善されるので,特別にinteger2が他と何か違うのかと
思いこんでおりました...基本的なところがきちんと勉強できていないようです...

 今回の件は過去ログにも無さそうでしたのでもしかすると,VBに堪能な
方々にとってはかなり当たり前の内容だったのかも知れませんが,
ご親切にアドバイスいただけて助かりました.どうもありがとうございました.
魔界の仮面弁士様にアドバイスいただけて光栄です.
 自己解決できるよう励んでまいりますので,今後もどうぞよろしくお願いいたします.
どうもありがとうございました!!

[ツリー表示へ]
タイトルRe^3:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9337
投稿日: 2009/09/02(Wed) 11:01
投稿者camputer
 こんにちは、camputerです。
 すみません。もう一度だけ質問させてください。一度だけ開放できた症状を見ましたが、
解決直後に再び開放できない現象になってしまいました。
色々テストし続けてみましたが、解決いたしません。。
アドバイスいただきたくお願い申し上げます。


Private Sub 練習
 call Excel練習(String3)
End Sub

Private Sub Excel練習(ByVal String3 As String)
・・・
 Dim Shape1 As Excel.Shape
・・・
 subroutine1(String1, String2, Shape1, String3, Integer1, Integer2)
                         '↑ここの行が原因です
・・・
End Sub


Sub subroutine1(ByVal String1 As String, ByVal String2 As String _
              , ByVal Shape1 As Excel.Shape, ByVal String3 As String _
              , ByRef Integer1 As Integer, ByRef Integer2 As Integer)

   '※Subroutine内のコードは無し
End Sub

 テストいたしましたところ、
subroutine1(String1, String2, Shape1, String3, Integer1)だと間違いなく開放できますが、
subroutine1(String1, String2, Shape1, String3, Integer1, Integer2)だと開放できません。。


 魔界の仮面弁士様からAs〜のご指摘をいただけたので、特別にInteger2が問題の場合以外にも、
全体として開放しにくいコーディングの複合要因が原因で起こる現象のように感じましたので、
最初のサブルーチンから2度引数として渡してあるString3についても
一度別の変数に入れてみたり、subroutine1の引数から消したりしましたが、
改善いたしません。。。
 ByVal Shape1 As Excel.Shape についても考えてみたのですが、過去ログにいくつか
(ByVal Wb As Excel.Workbook・・・)といったような宣言を見かけますので、
大丈夫なのかな?と思うのですが。。。

どこか怪しそうなところを御指摘いただけないでしょうか。。。

 どうぞよろしくお願いいたします。

[ツリー表示へ]
タイトルRe^4:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9340
投稿日: 2009/09/02(Wed) 13:50
投稿者るしぇ
そもそも、Excelオブジェクトの解放処理は実行しているのですか?

[ツリー表示へ]
タイトルRe^5:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9342
投稿日: 2009/09/02(Wed) 14:29
投稿者camputer
 るしぇ様

 どうもありがとうございます!
引数の内、Dim myShape As Excel.Shapeで宣言しているものにつきましては

使い終わる度に、MRComObject(myShape) : myShape = Nothing としております。
MRComObjectについては、http://hanatyan.sakura.ne.jp/dotnet/Excel01.htmのコードを
ずっと使わせていただいています。
  
    Public Shared Sub MRComObject(Of T As Class) _
           (ByRef objCom As T, Optional ByVal force As Boolean = False)
        If objCom Is Nothing Then
            Return
        End If
        Try
            If System.Runtime.InteropServices.Marshal.IsComObject(objCom) Then
                If force Then
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(objCom)
                Else
                    Dim count As Integer = _
                      System.Runtime.InteropServices.Marshal.ReleaseComObject(objCom)
                    Debug.WriteLine(count)
                End If
            End If
        Finally
            objCom = Nothing
        End Try
    End Sub



 他の宣言文
     Dim myBook As Excel.Workbook
        Dim myBooks As Excel.Workbooks = myApp.Workbooks
        Dim xlSheet As Excel.Worksheet
        Dim xlSheets As Excel.Sheets
        Dim MyChartObjects As Excel.ChartObjects
        Dim MyChartObject As Excel.ChartObject
        Dim MyChart As Excel.Chart
等についても、同様にMRComObjectで開放しているつもりですが、サブルーチンの引数にある
他のInteger、String等については開放処理しておりません。
(他のサブルーチンでは開放処理せずともExcel.Exeが無事に消えますので。。。)
 何かお気づきになる点がございましたら、是非ともご指摘いただきたくお願い申し上げます。

[ツリー表示へ]
タイトルRe^6:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9347
投稿日: 2009/09/03(Thu) 11:34
投稿者るしぇ
関係ない話が混ざってて良く分かりません。

ReleaseComObject しなければいけないのは参照カウンタを増加させることで参照
されていると判断する、外部の COM オブジェクト。つまり今回の場合
Excel オブジェクトのみです。Integer や String は VB 内部の管理下にあり、
そもそも対象外です。

サブルーチンだからというのも基本的には関係ありません。引数の型指定の注意を
受けたのは暗黙の型変換をさせないためで、その中でも対象は Shape1 のみです。
型指定した時点でサブルーチンは関係ないと思っていいでしょう。

> 使い終わる度に、MRComObject(myShape) : myShape = Nothing としております。
>  他の宣言文
> ・・・
> 等についても、同様にMRComObjectで開放しているつもりですが、
これに抜けがあると考えるのが通常です。
で、サブルーチンを変更したら解放できたとのことですが、たまたま解放できる
ことがあります。サブルーチンから離れた方がいいでしょう。

Integer や String は直接の原因ではありません。そこを変更するときに、他の
コードも変更していませんか?もしくは処理条件が変わり、実行される処理が
変わっていませんか?該当の Integer や String へ値を入れる時に Excel
オブジェクトを使っていませんか?その解放処理に抜けがありませんか?
http://hanatyan.sakura.ne.jp/dotnet/Excelflm.htm
本サイトに纏められている通り、同じ変数を使用しても参照しているオブジェクト毎に
毎回解放する必要があり、省略形や暗黙の型変換でコードに現れていない Excel
オブジェクトが裏で使用される場合があります。

そういったことも含めた、Excel オブジェクトの解放漏れをチェックしてください。

[ツリー表示へ]
タイトルRe^7:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9348
投稿日: 2009/09/03(Thu) 14:17
投稿者camputer
 るしぇ 様
 どうもありがとうございます!!
度々、有名な上級者の方からアドバイスいただけて光栄です。

 午前中に複数のPCでテストしてみると、開放できるものがありましたので、
コードの他の気になる箇所をなおして見ると現象が改善いたしました!

ビルド実行→メッセージボックス「終了」→停止

とする間、Excel.Exeの動きを観察しておりますが、わざとメッセージボックスの「OK」
を押さずに待機していると、すぐにExcel.Exeが無くなる時もあれば、
なぜかメッセージボックスを閉じるまでExcel.Exeが残るときもあります。
PCのスペックの低さか何かが原因なのかな?などと考えておりますが。。。
とりあえず、アドバイスいただけた後の修正で開放はできるようになったようです。
どうもありがとうございます。

>たまたま解放できることがあります。
>サブルーチンから離れた方がいいでしょう。
>Integer や String は VB 内部の管理下にあり、
と教えていただいたけたので、いろいろはっきり分かったので良かったです。
どうもありがとうございました。
 なぜか
If myShape.Type = 6 Then
のような行を
Dim myShapeType As Integer = myShape.Type
If myShapeType = 6 Then
とすると開放されやすくなったりしました。
 なぜIntegerで引っかかるのか自分でも予測できない現象だったので混乱しましたが、
いろいろアドバイスいただけて、かなり開放しやすいコーディングができるようになりました。
これを期に、自作アプリを色々なOSやスペックを変更して実行・検証するようにしてみます。

 VB界のVipの方々からアドバイスいただけたので非常に光栄です!
どうもありがとうございました!

[ツリー表示へ]
タイトルRe^8:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9349
投稿日: 2009/09/03(Thu) 15:44
投稿者るしぇ
普通に Excel を使用したときと同じく、Excel は開いたファイルの排他制御とか
やってるので、プロセスが終了するまで時間が掛かる場合があります。
ファイルサイズが大きい場合、保存処理に時間が掛かる場合もあります。
あまりシビアにプロセスのチェックをすると、解放できているのにチェックに
引っ掛かるかもしれません。

>なぜかメッセージボックスを閉じるまでExcel.Exeが残るときもあります。
そのメッセージボックスが本サイトの
> MessageBox.Show("まだ Excel.EXE が起動しています。")
であれば、解放できていない可能性が高いです。
メッセージボックスが原因ではなく、メッセージボックスで止めていると
関数内で処理が止まっているということなので、メッセージボックスを
閉じることで関数を抜け、関数内で使用していたリソースが使われなく
なるタイミングで、たまたま解放されているのでは無いでしょうか?。

解放処理が正しく行なわれていなくとも、たまたまプロセスが消えてくれる
ことはあると書きましたが、逆はありません。解放処理を正しく実行できて
いれば、メッセージボックスとは関係なく、プロセスは必ず消えます。

> If myShape.Type = 6 Then
> のような行を
> Dim myShapeType As Integer = myShape.Type
> If myShapeType = 6 Then
> とすると開放されやすくなったりしました。
myShape の対象が変化していませんので、関係ありません。
こちらの環境では以下のコードでプロセスは100%消えます。
(xlSheet についてのコードは省いてあります)
        Dim myShapes As Excel.Shapes
        Dim myShape As Excel.Shape
        
        myShapes = xlSheet.Shapes
        myShape = myShapes.AddLabel(Microsoft.Office.Core.MsoTextOrientation.msoTextOrientationDownward, 10, 10, 10, 10)
        If myShape.Type = 6 Then
        End If
        MRComObject(myShape)
        MRComObject(myShapes)

[ツリー表示へ]
タイトルRe^9:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9350
投稿日: 2009/09/03(Thu) 20:06
投稿者camputer
 るしぇ 様

 どうもありがとうございます!!
度々のアドバイス光栄でございます.またテストできることが増えます^^

>関数内で使用していたリソースが使われなくなるタイミングで、
たまたま解放されているのでは無いでしょうか
 どうもありがとうございます.VB花ちゃんの「解放」の記事にはかなり
勉強させていただきましたが,今回アドバイスいただいた
「'テスト中は、下記コードを 上記 Excel 終了後に実施するようにして下さい。」
については,そういえばまだ試しておりませんでした.
(いつもタスクマネージャから強制終了してました...
解放の判定も,タスクマネージャに残るor残らないで判断しておりましたので...)
今からすぐに使わせていただきます.
 今回教えていただいたmsoTextOrientationDownwardも知りませんでしたので,
一緒に調べてみます!
(納得できるまでテストしきるのに多少時間がかかるかもしれませんので,
まずお礼だけ投稿させていただきます.またご報告させていただきます!)
 本当にどうもありがとうございます!!

[ツリー表示へ]
タイトルRe^10:  Subroutineの引数が原因でExcelが開放できなくなります。
記事No9351
投稿日: 2009/09/04(Fri) 21:13
投稿者camputer
 るしぇ 様
 どうもありがとうございました!

 教えていただいた
>解放処理が正しく行なわれていなくとも、たまたまプロセスが消えてくれることはあると〜
を考慮した上で再度,コードを一か所ずつ消しながら怪しい個所をスクリーニングして
みましたところ,怪しい個所がExcel関連のオブジェクトで2か所見つかりました!

 私が今までずっと勉強していたような数値計算言語では,どんなに長いコードであっても
バグ取りの際にある引数を消して症状が改善した場合は,間違いなくその引数か
それの上流にある式が100%原因なので,それが身体にしみついていたようです...orz
今コーディングしている.NETでも,一度でも解放される現象が生じた場合,その流れまでに
バグは無いと思いこんでおりました.今回はその原因であるはずのものが「Integer」だったので
一人で悩みましたが...
 あともしかするとExcel関連のオブジェクト以外が原因なのではないか?と思うような
症状が共通してありました.DataGridViewなのですが,
 Sub Excel練習
  ・・・
  Call DataGridView_Rows_Add(String1 As String, String2 As String, _
                               String3 As String, String4 As String, _
                               Integer1 As Integer, Integer2 As Integer)
  ・・・
 End Sub
のようなExcelオブジェクトを含まないサブルーチンの中のオブジェクト解放はほとんど
気にしておりませんでしたが,このCall文をコメントアウトするとExcel.Exeが必ず消える,
といった現象がありました.スペックが低いPCで動作させた時の現象でしたが,
もしかすると(VB素人の考えでございます^^;),
もともとExcelがきちんと解放されていないがたまたまうまく消えやすいようなコードで,
更に他の解放できていないオブジェクトが多く生まれるとExcel関連の参照の解放に
影響が出るのかな???と思うのですが...
 一番初めに質問させていただいた
>subroutine1(String1, String2, Shape1, String3, Integer1, Integer2)
>                                '↑ここの行が無ければ開放されます。。

>subroutine1(String1, String2, Shape1, String3, Integer1) 
>だと開放できるので、〜
についても,Integer2はそのsubroutine1の中で呼び出すDataGridViewの行番号でございます.

 今回は色々と勉強することができました.見つけた怪しい個所については,今MSDNで
調べておりますが,解決策が見つかりません...
質問内容が全然違うものになってしまうのと,十分すぎるくらいのアドバイスをいただけましたので
今後の閲覧者の方々にわかりやすいよう新しいスレッドで質問させていただきます.

 この度は本当にどうもありがとうございました!
VB界の有名な方々に閲覧・アドバイスしていただけて非常に光栄です.
(素人質問で僭越でございます..)今後もどうぞよろしくお願いいたします.

[ツリー表示へ]