DOBON.NET DOBON.NETプログラミング掲示板過去ログ

フックについて

環境/言語:[xp]
分類:[.NET]

ユーザフォーム内にtextboxとbuttonを配置して、buttonを押すとtextboxの右クリックができないようするコードを書きました。
buttonを押すと、右クリックしない状態になるのですが、しばらくすると、
[System.NullReferenceException' のハンドルされていない例外が 不明なモジュールです。 で発生しました。

追加情報 : オブジェクト参照がオブジェクト インスタンスに設定されていません。]とエラーがでてしまうのです。なぜこうなるのか見当がつかないのですが
もしわかる人がいれば教えていただきたいのですが・・・
'-----form内-------

Public Delegate Function WindowProc_delegate(ByVal hWnd As IntPtr, ByVal uMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As WindowProc_delegate) As Integer

Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Integer, ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer


Dim moto As Integer

Public Function WindowProc(ByVal hWnd As IntPtr, ByVal uMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

Select Case uMsg

Case &H7B '右クリック禁止

Exit Function

End Select


CallWindowProc(moto, hWnd, uMsg, wParam, lParam)

End Function





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

Dim dd As WindowProc_delegate
dd = AddressOf WindowProc
moto = SetWindowLong(Me.TextBox1.Handle, -4, dd)

End Sub
API関数を使うより、TextBoxを継承したクラスを作成して、
そのTextBoxのWndProcメソッドをオーバーライドした方が
簡単でよいと思いますが、それはそれとして・・・

> Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
>
> Dim dd As WindowProc_delegate
> dd = AddressOf WindowProc
> moto = SetWindowLong(Me.TextBox1.Handle, -4, dd)
>
> End Sub

ここで作成したWindowProc_delegate型のインスタンスを保持している変数ddは
Button_Clickイベント内でのみのスコープですので、
Button_Clickイベントの処理が終わると無効になります。
その結果、変数ddに保持されていたインスタンスはしばらくして、
ガベージコレクションにより回収されてしまいます。
そして、SetWindowLongがコールバック関数を呼び出す時点で、
回収されていれば、例外が発生します。

変数ddをButton_Click内で定義するのではなく、
そのフォームのPrivate変数に変えれば、フォームが生きている間は、
大丈夫ですよ。
2005/05/24(Tue) 01:17:22 編集(投稿者)

> 追加情報 : オブジェクト参照がオブジェクト インスタンスに設定されていません。]とエラーがでてしまうのです。なぜこうなるのか見当がつかないのですが
> もしわかる人がいれば教えていただきたいのですが・・・

こんにちは。

フックというか、サブクラス化を行っているのですね?
通常.NETでは一貫した関数ポインタの値というものが存在しません。
従って、勝手にそれを変えて自前で保存しておくのは危険です。

通常、サブクラス化と同等のことをするならば、親クラスを
継承して、WndPorcをオーバーライドします。
そうでなく、関数ポインタのあたりをお任せしたサブクラス化は
NativeWindowクラスを使用してできます。
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpref/html/frlrfsystemwindowsformsnativewindowclasstopic.asp
変数ddをButton_Click内で定義するのではなく、
そのフォームのPrivate変数に変えれば、フォームが生きている間は、
大丈夫ですよ。

その通りでした。ありがとうございました。

ちなみに、

通常.NETでは一貫した関数ポインタの値というものが存在しません。
従って、勝手にそれを変えて自前で保存しておくのは危険です
ということですが、このコードを使っていたら、やはりフリーズしてしまうのでしょうか?
解決済み!
> 通常.NETでは一貫した関数ポインタの値というものが存在しません。
> 従って、勝手にそれを変えて自前で保存しておくのは危険です
> ということですが、このコードを使っていたら、やはりフリーズしてしまうのでしょうか?
>

私も以前同様の方法でサブクラス化を試みたことがあります。
しかし、関数のポインタを保存しておく変数をフォームレヴェルの
ものにしても、上記のエラーがでて解決されませんでした。
そこで、自前でのサブクラス化はやめて、NativeWindowクラスを使用しました。
参考までに…。

DOBON.NET | プログラミング道 | プログラミング掲示板