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