tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re^5: 突然発生するようになったエラー
投稿日: 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 時にエラーになっているのではなく、
最初にフォームを表示する場合にすらエラーになっているのだとしたら、
別の問題かも知れません。(フォームではなくコントロールで障害が起きているなど)

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。