I would like to know if this code can be adapted to use it inside a normal class (Example: Form1 Class) to don't need subclassing a Control.
Code is from BlueMonkMN
here Capture the option selected by the user in a windows default contextmenu?
Class MyTextBox : Inherits TextBox
Public Enum ContextCommands
WM_CUT = &H300
WM_COPY = &H301
WM_PASTE = &H302
End Enum
Public Class ContextCommandEventArgs
Inherits EventArgs
Public Property Command As ContextCommands
End Class
Event OnCut(sender As Object, e As ContextCommandEventArgs)
Event OnCopy(sender As Object, e As ContextCommandEventArgs)
Event OnPaste(sender As Object, e As ContextCommandEventArgs)
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
Select Case m.Msg
Case ContextCommands.WM_CUT
RaiseEvent OnCut(Me, New ContextCommandEventArgs() With {.Command = ContextCommands.WM_CUT})
Case ContextCommands.WM_COPY
RaiseEvent OnCopy(Me, New ContextCommandEventArgs() With {.Command = ContextCommands.WM_COPY})
Case ContextCommands.WM_PASTE
RaiseEvent OnPaste(Me, New ContextCommandEventArgs() With {.Command = ContextCommands.WM_PASTE})
End Select
End Sub
End Class
To understand better my problem, I'll show you what I've tried to adapt it:
Public Class Form1
Public Enum ContextCommands
WM_CUT = &H300
WM_COPY = &H301
WM_PASTE = &H302
End Enum
Public Class ContextCommandEventArgs
Inherits EventArgs
Public Property Command As ContextCommands
End Class
Event OnCut(TextBox1 As Object, e As ContextCommandEventArgs)
Event OnCopy(TextBox1 As Object, e As ContextCommandEventArgs)
Event OnPaste(TextBox1 As Object, e As ContextCommandEventArgs)
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
Select Case m.Msg
Case ContextCommands.WM_CUT
RaiseEvent OnCut(TextBox1, New ContextCommandEventArgs() With {.Command = ContextCommands.WM_CUT})
Case ContextCommands.WM_COPY
RaiseEvent OnCopy(TextBox1, New ContextCommandEventArgs() With {.Command = ContextCommands.WM_COPY})
Case ContextCommands.WM_PASTE
RaiseEvent OnPaste(TextBox1, New ContextCommandEventArgs() With {.Command = ContextCommands.WM_PASTE})
End Select
End Sub
Private Sub TextBox1_OnTextCommand() Handles TextBox1.TextChanged
If WM_CUT then...
Elseif WM_COPY then...
Elseif WM_Paste then...
End if
End Sub
Private Sub TextBox1_OnTextCommand() Handles Me.OnPaste, Me.OnCopy, Me.OnCut
MsgBox("Activated")
End Sub
End Class
This is not a simple task for a VB developer, but I hope this helps. The code no longer relates to a specific textbox, but you should be able to identify which textbox caused the event by comparing cwp.hWnd
with TextBox.Handle
values if you need to. EditMenuHook.Enable
should probably only be called once at the beginning of your application to turn on the hook, and once at the end to turn it off.
Imports System.Runtime.InteropServices
Public Class Form1
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
EditMenuHook.Enable(True)
End Sub
Protected Overrides Sub OnClosed(e As EventArgs)
EditMenuHook.Enable(False)
MyBase.OnClosed(e)
End Sub
End Class
Friend Class EditMenuHook
Public Structure CWPSTRUCT
Public lParam As IntPtr
Public wParam As IntPtr
Public message As UInt32
Public hWnd As IntPtr
End Structure
Public Delegate Function CallBack( _
ByVal nCode As Integer, _
ByVal wParam As IntPtr, _
ByVal lParam As IntPtr) As Integer
Shared hHook As Integer = 0
'Import for the SetWindowsHookEx function.
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Public Overloads Shared Function SetWindowsHookEx _
(ByVal idHook As Integer, ByVal HookProc As CallBack, _
ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer
End Function
'Import for the CallNextHookEx function.
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Public Overloads Shared Function CallNextHookEx _
(ByVal idHook As Integer, ByVal nCode As Integer, _
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function
'Import for the UnhookWindowsHookEx function.
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Public Overloads Shared Function UnhookWindowsHookEx _
(ByVal idHook As Integer) As Boolean
End Function
Private Const WH_CALLWNDPROC = 4
Public Enum TextCommandMessage
WM_CUT = &H300
WM_COPY = &H301
WM_PASTE = &H302
End Enum
'Keep the reference so that the delegate is not garbage collected.
Private Shared hookproc As CallBack
Shared Sub Enable(enable As Boolean)
If hHook = 0 AndAlso enable = True Then
hookproc = AddressOf EditCommandHook
hHook = SetWindowsHookEx(WH_CALLWNDPROC, _
hookproc, _
IntPtr.Zero, _
AppDomain.GetCurrentThreadId())
If hHook.Equals(0) Then
MsgBox("SetWindowsHookEx Failed")
Return
End If
ElseIf hHook <> 0 AndAlso enable = False Then
Dim ret As Boolean = UnhookWindowsHookEx(hHook)
If ret.Equals(False) Then
MsgBox("UnhookWindowsHookEx Failed")
Return
Else
hHook = 0
End If
End If
End Sub
Public Shared Function EditCommandHook( _
ByVal nCode As Integer, _
ByVal wParam As IntPtr, _
ByVal lParam As IntPtr) As Integer
If nCode < 0 Then
Return CallNextHookEx(hHook, nCode, wParam, lParam)
End If
Dim cwp = DirectCast(System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, GetType(CWPSTRUCT)), CWPSTRUCT)
Select Case cwp.message
Case TextCommandMessage.WM_CUT
System.Diagnostics.Debug.WriteLine(String.Format("Cut {0}", cwp.hWnd))
Case TextCommandMessage.WM_COPY
System.Diagnostics.Debug.WriteLine(String.Format("Copy {0}", cwp.hWnd))
Case TextCommandMessage.WM_PASTE
System.Diagnostics.Debug.WriteLine(String.Format("Paste {0}", cwp.hWnd))
End Select
Return CallNextHookEx(hHook, nCode, wParam, lParam)
End Function
End Class