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

TextBox右クリック時メニュー表示を抑止する処理でエラー

環境/言語:[OS : Windows XP Home Edition / 言語 : Visual Basic .NET / .NET Framework : 1.1]
分類:[.NET]

お世話になっております。
(いたずら返信防止のため、検索でヒットしない名前に変えました)

TextBoxへのペーストを避ける必要から、

http://dobon.net/vb/dotnet/control/tbnocontextmenu.html

こちらの記事とそのコメントにある内容を試しましたが
(CAT-chyさんのコードはC#からVBに移して実行しました)
右クリックした状態でマウスを上または左に動かすとCShortでオーバーフローが発生します。
ReleaseCaptureを呼ぶ条件を判定する処理の内容を理解できていないので
VBで正しくキャストする方法もわからないのですが、
ReleaseCaptureのタイミングはTextBoxの境界を越えるときかと思います。
しかし必ずしもそこではなく、マウスが動いたのを検出した時点で呼んでしまっても
よいのではないかと考え(全く自信はないのですが)、次のようにしてみました。

Public Class MyTextBox
    Inherits TextBox
    Private Const WM_PASTE As Integer = &H302
    Private Const WM_MOUSEMOVE As Integer = &H200
    Private Const WM_RBUTTONDOWN As Integer = &H204
    Private Const MK_RBUTTON As Integer = &H2
    Private mouseIsCaptured As Boolean
    Public Sub New()
        Me.ContextMenu = New ContextMenu
    End Sub
    <System.Runtime.InteropServices.DllImport("USER32.DLL", EntryPoint:="ReleaseCapture")> _
    Public Shared Sub ReleaseCapture()
    End Sub
    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            Case WM_PASTE
                Return
            Case WM_RBUTTONDOWN
                mouseIsCaptured = True
            Case WM_MOUSEMOVE
                If (m.WParam.ToInt32 And MK_RBUTTON) <> 0 And mouseIsCaptured Then
                    ReleaseCapture()
                    mouseIsCaptured = False
                End If
        End Select
        MyBase.WndProc(m)
    End Sub
End Class

一見正常に動作しますが、これで問題はないでしょうか。
2007/03/03(Sat) 08:32:26 編集(投稿者)

mouseIsCapturedをWndProcの中でstaticとして宣言するほうがよいですね。
最初そのようにしてうまく動作しなかったので上のように変えていたのですが、別のところにバグがあったようで、その後staticに戻すと正常に動作するようになりました。

--------
追記です。一見正常に動作していますが、WM_MOUSEMOVEでReleaseCaptureすること自体の正否はわからず、何かまずいことをしているかもしれないと思いますので、ご教示のほどお願いします。
2007/03/03(Sat) 10:31:18 編集(投稿者)

■No19236に返信(千八之介さんの記事)

# 敬称が抜けていたので修正。

千八○○(一応伏せ字)さんから千八之介さんに改名されたのですね。

えーと、元のどぼん!さんの記事は、できるだけ簡単にやろうという感じがした
のですが、CAT-chy さんのコメントではそれではダメなのでこういう方が良いの
では?という話なのですね。

で、元々のきっかけが「コンテキストメニューを出さない」的な話だと思ったわ
けですけれども、それならば WM_MOUSEMOVE やらゴチャゴチャやらずとも、
WM_CONTEXTMENU を無効にしてしまえばなんとかなるのではないかしらん?と思っ
たのですが、それではダメでしょうか。
C# で恐縮ですが、とりあえずこんな感じで。

    protected override void WndProc(ref Message m)
    {
        const int WM_CONTEXTMENU = 0x007B;
        if (m.Msg == WM_CONTEXTMENU)
        {
            return;
        }

        base.WndProc(ref m);
    }

単にペーストを無視するだけであれば、千八之介さんがすでに書かれているよう
にWM_PASTE を何もしないようにするだけでいいかもしれません。

# 結局のところ「なにがしたいのか」が元質問からうまく導き出せなかったので
# ちょっと苦労しました
■No19239に返信(ぽぴ王子さんの記事)

簡単な方法があったのですね。以下のようにして解決しました。

    Protected Overrides Sub WndProc(ByRef m As Message)
        Const WM_PASTE As Integer = &H302
        Const WM_CONTEXTMENU As Integer = &H7B
        Select Case m.Msg
            Case WM_PASTE, WM_CONTEXTMENU
                Return
        End Select
        MyBase.WndProc(m)
    End Sub

ありがとうございました。
解決済み!

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