tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトル突然発生するようになったエラー
記事No10643
投稿日: 2012/01/16(Mon) 23:50
投稿者たけ
はじめまして、たけ と申します。
Javaばかり行っていたため、VB.netは3か月ほどで、
内部処理や設定のパラメータなどについては理解不足です。

(環境)
Windows XP
VB.net2003,サービスパック1.1

さっそくですが、質問をさせていだきます。
モジュールを変えていないのに、急に「破棄されたオブジェクトにアクセスできません」
というエラーが発生するようになってしまいました。
発生する原理(インスタンスが削除されてしまって発生する)は理解しているつもりです。

しかし、いくつかの端末で同じモジュール利用していますが、
エラーの発生する端末と発生しない端末があり困っています。
・モジュールも変えていません。
・VB.netの設定等も故意には変えていません。
・VBの提供しているコントロールのShow()内のCreateHandle()内で発生
・エラーの発生しない端末で、Show()の前に対象オブジェクトをDisposeすると
同様のエラーが発生する。(ためしにモジュールを書き換え実験しました)

端末に依存するものではないかと考えていますが、
端末にどのような変化がおきて発生するようになってしまったのでしょうか。
発生する端末と発生しない端末の比較などを行っていますが、
比較する項目の数が膨大で見当もつきません。

助けていただきたく思っております。
よろしくお願いいたします。

[ツリー表示へ]
タイトルRe: 突然発生するようになったエラー
記事No10644
投稿日: 2012/01/17(Tue) 02:07
投稿者魔界の仮面弁士
> VB.net2003,サービスパック1.1
サービスパックに小数点はありません。
.NET Framework 1.1 Service Pack 1 のことでしょうか?

> 急に「破棄されたオブジェクトにアクセスできません」
> というエラーが発生するようになってしまいました。
検索キーワードとしては、「ObjectDisposedException CreateHandle」でしょうかね。

> 発生する端末と発生しない端末の比較などを行っていますが、
再現性はありますか? 問題の発生する端末では 100% の確率で起きるのか、
また、発生するのは特定の処理後の Show だけなのか、それとも処理に関係なく
メインフォームの初回起動時に起きてしまうのかなど。

> 比較する項目の数が膨大で見当もつきません。
・それぞれの実行環境の .NET Framework 1.1 に Service Pack は適用済みですか?

・共有されている資源(Icon, Picture, Font 等)をどこかで破棄していませんか?
 http://d.hatena.ne.jp/ladybug/20050915

・閉じたフォームを再度 Show しようとしていませんか?

・DoEvents メソッドを不用意に呼び出している個所はありませんか?

・UIスレッド以外からフォームやコントロールを操作していませんか?

[ツリー表示へ]
タイトルRe^2: 突然発生するようになったエラー
記事No10645
投稿日: 2012/01/17(Tue) 07:39
投稿者たけ
魔界の仮面弁士様

様々な考察をいただきありがとうございます。
与えてくださったキーワードをもとにさらに調べていきたいと思います。

> > VB.net2003,サービスパック1.1
> サービスパックに小数点はありません。
> .NET Framework 1.1 Service Pack 1 のことでしょうか?
>
ご指摘の通りです。ありがとうございます。

> > 急に「破棄されたオブジェクトにアクセスできません」
> > というエラーが発生するようになってしまいました。
> 検索キーワードとしては、「ObjectDisposedException CreateHandle」でしょうかね。
Exceptionのクラスも調べました。そのキーワードです。

> > 発生する端末と発生しない端末の比較などを行っていますが、
> 再現性はありますか? 問題の発生する端末では 100% の確率で起きるのか、
> また、発生するのは特定の処理後の Show だけなのか、それとも処理に関係なく
> メインフォームの初回起動時に起きてしまうのかなど。
問題の端末のひとつの処理で必ず発生します。
各機能の共通モジュールで発生します。

> > 比較する項目の数が膨大で見当もつきません。
> ・それぞれの実行環境の .NET Framework 1.1 に Service Pack は適用済みですか?
はい、適用済です。
数日前まで正常にうごいていました。

> ・共有されている資源(Icon, Picture, Font 等)をどこかで破棄していませんか?
>  http://d.hatena.ne.jp/ladybug/20050915
今日調べてみます。

> ・閉じたフォームを再度 Show しようとしていませんか?
記述的には閉じたフォームをshowしてるのですが、
2003年からそのモジュールでエラーなく動作していました。
瞬時の間にガベージコレクションで破棄されると
考えられるのでしょうか。
問題端末のモジュールを実験的には変更できないので
どのように調べればわかりますでしょうか。

> ・DoEvents メソッドを不用意に呼び出している個所はありませんか?
> ・UIスレッド以外からフォームやコントロールを操作していませんか?
上と同じです。
しかし、このキーワードでもさらに調べてみたいと思います。

[ツリー表示へ]
タイトルRe^3: 突然発生するようになったエラー
記事No10646
投稿日: 2012/01/17(Tue) 12:28
投稿者魔界の仮面弁士
> > ・閉じたフォームを再度 Show しようとしていませんか?
> 記述的には閉じたフォームをshowしてるのですが、
> 2003年からそのモジュールでエラーなく動作していました。

動作しているのが、運が良かったとみるべきでしょう。

http://msdn.microsoft.com/ja-jp/library/system.windows.forms.form.close%28vs.71%29.aspx
》 モードレス ウィンドウとして表示されている Form で Close メソッドが
》 呼び出された場合は、フォームのリソースが既に解放されているため、
》 Show メソッドを呼び出してフォームを表示することはできません。
》 フォームを非表示にした後で表示するには、Hide メソッドを使用します。


再度開きなおす必要があれば、閉じるのではなく「非表示」にすべきですし、
閉じられた後であるならば、再度 New しなおすのが正しい動作です。
http://w.livedoor.jp/pg-note/d/Form%A4%CE%C9%BD%BC%A8/%C8%F3%C9%BD%BC%A8%CA%FD%CB%A1%A4%CB%A4%E8%A4%EB%C6%B0%BA%EE%A4%CE%B0%E3%A4%A4
http://dobon.net/vb/bbs/log3-1/575.html
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.form.close.aspx


> 瞬時の間にガベージコレクションで破棄されると
> 考えられるのでしょうか。
この場合、ガベージコレクションは関係ありません。その前の段階ですね。


> 問題端末のモジュールを実験的には変更できないので
> どのように調べればわかりますでしょうか。
side-by-side バージョンとして、修正版を別フォルダに配置して試せませんか?

[ツリー表示へ]
タイトルRe^4: 突然発生するようになったエラー
記事No10647
投稿日: 2012/01/17(Tue) 12:48
投稿者たけ
魔界の仮面弁士様

ご返答いただきありがとうございます。


> 動作しているのが、運が良かったとみるべきでしょう。
>
> http://msdn.microsoft.com/ja-jp/library/system.windows.forms.form.close%28vs.71%29.aspx
> 》 モードレス ウィンドウとして表示されている Form で Close メソッドが
> 》 呼び出された場合は、フォームのリソースが既に解放されているため、
> 》 Show メソッドを呼び出してフォームを表示することはできません。
> 》 フォームを非表示にした後で表示するには、Hide メソッドを使用します。
Closeとdisposeの違いが明確に理解できていませんが、
cIoseしたリソースには再びnewしない限りアクセスできないのですね。
createhandleの中でハンドルが作成される際、
再びインスタンスが生成されるようなことはあるのでしょうか。


> この場合、ガベージコレクションは関係ありません。その前の段階ですね。
参照を削除したわけではないのでガベージコレクションと関係ない、
という判断で正しいでしょうか。

> > 問題端末のモジュールを実験的には変更できないので
> > どのように調べればわかりますでしょうか。
試す、ということができません。
原因が判明し理由を明確にした上で、モジュールの置き換えなどか可能になります。

[ツリー表示へ]
タイトルRe^5: 突然発生するようになったエラー
記事No10648
投稿日: 2012/01/17(Tue) 15:12
投稿者魔界の仮面弁士
> Closeとdisposeの違いが明確に理解できていませんが、
Close は「閉じる」、Dispose は「破棄する」です。
そして Form の Close メソッドは、内部で Dispose も呼び出しています。(※1)

Dispose 等にて IsDisposed = True の状態になった後では、
幾つかのプロパティやメソッドが失敗するようにできており、
これが今回の要因となっています。



> 原因が判明し理由を明確にした上で、モジュールの置き換えなどか可能になります。
原因はともかくとして、不具合の理由は明確だと思いますよ。(※2)

公式資料である MSDN Library にも、Close 後の Show は行えないと
明記されているわけですし、Close 後に Show するだけの検証用アプリを
実際に動かしてみれば、問題点の再現検証もできますよね。


なお、手元の環境は Win7 なので .NET 1.1 のテストはできませんが、
下記のコードを .NET 2.0 版の VBC.EXE でコンパイルしてみたところ、
やはり Close 後の Show を呼び出した段階で例外が発生していました。


Imports System
Imports System.Windows.Forms
Module Sample
  Public Sub Main()
    Dim F As Form
    F = New Form()
    F.Text = "Form"
    F.Show()
    MsgBox("フォームを閉じます。")
    F.Close()
    MsgBox("閉じられたフォームを再表示します。")
    Try
      F.Show()
      MsgBox("フォームが再表示されました。閉じて破棄します。")
    Catch ex As Exception
      MsgBox(ex.GetType().FullName & vbCrLf & ex.Message & vbCrLf & ex.StackTrace)
    End Try
    F.Close()
    F.Dispose()
  End Sub
End Module


OS その他のセキュリティパッチなど、何らかの条件を満たすことで
今まで動いていたのかも知れませんが、少なくとも公式資料にて
「できない」と言われている以上、今まで正常動作しているように
見えていたとしても、それがいつまた動作しなくなるのかは、
たけさんも Micorosoft も保証できないと思います。

今まで動いていたので、動作する条件/動作しない条件を
切り分けたいという要求や事情は察しますが、本来 NG とされる処理を
引き続き「想定外の動作」に頼ったまま運用し続けるのは問題があるので、
状況を説明して修正要求を発するべきだと思いますよ。

とはいえ、問題の発生要因がこの点(Close 後の Show 呼び出し)だけで
あるのかどうかは、こちらでは分からないのですけれども。


> cIoseしたリソースには再びnewしない限りアクセスできないのですね。
全ての機能にアクセスできないわけではありませんが、今回の場合は Form の
 Protected Overridable Sub CreateHandle()
というメソッドが、その内部で
》    If Me.IsDisposed Then
》        '破棄されていた場合は例外を発生させる
》        Throw New ObjectDisposedException(MyBase.GetType().Name)
》    End If
に相当するコードが実行され、例外となっているようですね。


手元に該当バージョンの環境が無いため、後継バージョンでの
話となりますが、引数無しの Show メソッドの動作を見てみると、
内部的には「Me.Visible = True」と全く同じ動作となっているようです。

そして処理の流れを追ってみると、
 [Control] Show メソッド
 → [Control] Visible プロパティ
 → [Form] SetVisibleCore メソッド
 → [Control] Handle プロパティ
 → [Form/Control] CreateHandle メソッド
となっており、この段階で先の ObjectDisposedException になっていました。


> createhandleの中でハンドルが作成される際、
> 再びインスタンスが生成されるようなことはあるのでしょうか。
インスタンスがハンドルを管理しているのであって、
ハンドルによってインスタンスが生成されるわけでは無いですよ。

質問の意図がよく分かりませんが、ハンドルを強制的に
再生成したいという意味であれば、RecreateHandle メソッドを
利用することになっています。ただ、今回の処理においては、
(Re)CreateHandle を明示的に呼び出す必要は無いでしょうね。



> 参照を削除したわけではないのでガベージコレクションと関係ない、
> という判断で正しいでしょうか。
というよりも、「直接の原因ではない」という事です。
(間接的には関わってくる事もあるかも知れませんが)

そもそも ObjectDisposedException の例外は、破棄されたオブジェクトが
再利用されようとしたときに、それをブロックするための例外です。
破棄の要因が、ガベージコレクトによって自動回収された場合であろうと、
自分で Close(Dispose)した場合であろうと、ObjectDisposedException が
発生するという点では同じことです。



==== 以下、補足事項 ====

(※1) Close 時に Dispose されるのは、「モードレス」のフォームすなわち
フォームが Show メソッドで表示されていた場合の話です。

ShowDialog で「モーダル」のフォームとして表示されていた場合は、
Close メソッドを呼び出してもフォームが Dispose されることは
ありません。この場合は、閉じた後に続けて再利用することができます。

ただし、Close 時に Dispose されないということは、ShowDialog 利用時は
そのフォームを呼び出した側が、使用後に自分で Dispose しなければならない
ということも意味しています。万一 Dispose し忘れてもガベージコレクトで
回収はされますが、基本的には呼び出し側が Dispose の責任を負います。。

http://msdn.microsoft.com/ja-jp/library/c7ykbedk.aspx
》 ダイアログ ボックスとして表示されているフォームは
》 Close メソッドで閉じられることはないため、
》 フォームがアプリケーションで不要になった場合は、
》 そのフォームの Dispose メソッドを呼び出す必要があります。

==========

(※2) ただし、閉じた後の再 Show 時にエラーになっているのではなく、
最初にフォームを表示する場合にすらエラーになっているのだとしたら、
別の問題かも知れません。(フォームではなくコントロールで障害が起きているなど)

[ツリー表示へ]
タイトルRe^6: 突然発生するようになったエラー
記事No10651
投稿日: 2012/01/20(Fri) 12:30
投稿者たけ
魔界の仮面弁士様

より詳しい解説やアドバイスをありがとうございます。
今までなんとなくvbを触っていましたが今回の事象で
様々なことを学ぶことができました。
大変感謝しております。

おっしゃってくださった通り、想定外にうまくいってた処理に頼った運用でした。
近日のセキュリティパッチの更新で、問題が表面化したようでした。
ご協力いただき、大変助かりました。
本当にありがとうございました。

[ツリー表示へ]