有一应用程序正运行,其一窗口上有一控件:Combo1(就是下拉框),我知道其句柄。
我编写的程序中需要对该Combo1进行监控,如果其Text(就是下拉框显示值)发生变化,我就要
执行一段代码。
请问如何捕捉Combo1中值发生变化的这个事件?
我现在用的是最最土的方法:使用Timer,每隔10ms就通过Combo1的句柄来读取其值,然后判断是否变化了,这显然是不好的方法。
希望高手指点一二。
我编写的程序中需要对该Combo1进行监控,如果其Text(就是下拉框显示值)发生变化,我就要
执行一段代码。
请问如何捕捉Combo1中值发生变化的这个事件?
我现在用的是最最土的方法:使用Timer,每隔10ms就通过Combo1的句柄来读取其值,然后判断是否变化了,这显然是不好的方法。
希望高手指点一二。
(ByVal idHook As Long, _
ByVal lpfn As Long, _
ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long'idHook代表是何种Hook,有以下几种
Public Const WH_CALLWNDPROC = 4
Public Const WH_CALLWNDPROCRET = 12
Public Const WH_CBT = 5
Public Const WH_DEBUG = 9
Public Const WH_FOREGROUNDIDLE = 11
Public Const WH_GETMESSAGE = 3
Public Const WH_HARDWARE = 8
Public Const WH_JOURNALPLAYBACK = 1
Public Const WH_JOURNALRECORD = 0
Public Const WH_KEYBOARD = 2
Public Const WH_MOUSE = 7
Public Const WH_MSGFILTER = (-1)
Public Const WH_SHELL = 10
Public Const WH_SYSMSGFILTER = 6
Public Const WM_LBUTTONDOWN = &H201
Public Const CB_SETCURSEL = &H14E
Public Declare Function CallNextHookEx Lib "user32" _
(ByVal hHook As Long, _
ByVal ncode As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
Public Declare Function UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
Public hHook As LongPublic Sub UnHookKBD()
If hHook <> 0 Then
UnhookWindowsHookEx hHook
hHook = 0
End If
End SubPublic Function EnableKBDHook()
If hHook <> 0 Then
Exit Function
End If
hHook = SetWindowsHookEx(WH_MOUSE, AddressOf MyKBHFunc, App.hInstance, App.ThreadID)
End FunctionPublic Function MyKBHFunc(ByVal iCode As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
MyKBHFunc = 0 '表示要处理这个讯息
If wParam = 513 Then
Form1.Text1 = "左键点击"
End If
If wParam = 516 Then
Form1.Text1 = "右键点击"
End If
Form1.Text2 = lParamEnd Function
Call EnableKBDHook
End Sub
Private Sub Form_Unload(Cancel As Integer)
Call UnHookKBD
End Sub鼠标钩子的一个例子可以分辨鼠标左右键点击的例子
你需要知道combo被修改的时候触发的windows消息即可同样的写一个出来
Private hwnd5 As LongPrivate Sub Form_Load()
Dim ret As Long
'取得Combo内EditBox的hwnd
hwnd5 = FindEditInCombo(Combo1)
'记录原本的Window Procedure的位址
preWinProc = GetWindowLong(hwnd5, GWL_WNDPROC)
'设定EditBox的window Procedure到wndproc
ret = SetWindowLong(hwnd5, GWL_WNDPROC, AddressOf wndproc)
End SubPrivate Sub Form_Unload(Cancel As Integer)
Dim ret As Long
'取消Message的截取,而使之又只送往原来的Window Procedure
ret = SetWindowLong(hwnd5, GWL_WNDPROC, preWinProc)
End Sub'以下程式在.bas module
Option ExplicitDeclare Function EnumChildWindows Lib "user32" _
(ByVal hWndParent As Long, ByVal lpEnumFunc As Long, _
ByVal lParam As Long) As Long
Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
(ByVal hwnd As Long, ByVal lpClassName As String, _
ByVal nMaxCount As Long) As Long
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long) As Long
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As LongPublic Const GWL_WNDPROC = (-4)
Public Const WM_MOUSEMOVE = &H200
Public Const WM_RBUTTONDOWN = &H204
Public preWinProc As Long
Private hEditWnd As LongPublic Function wndproc(ByVal hwnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
'以下会截取mouse Rbutton Down
If Msg = WM_RBUTTONDOWN Then
Debug.Print "Combol Mouse RButton Down "
Else
'将之送往原来的Window Procedure
wndproc = CallWindowProc(preWinProc, hwnd, Msg, wParam, lParam)
End If
End Function
Public Function FindEditInCombo(ctl As ComboBox) As Long
Call EnumChildWindows(ctl.hwnd, AddressOf EnumFunc, 0)
FindEditInCombo = hEditWnd
End FunctionPublic Function EnumFunc(ByVal hwnd As Long, ByVal lParam As Long) As Long
Dim ClsName As String
Dim len5 As Long
If hwnd = 0 Then
EnumFunc = 0
Else
ClsName = String(255, 0)
len5 = GetClassName(hwnd, ClsName, 256)
ClsName = Left(ClsName, len5)
If ClsName = "Edit" Then
hEditWnd = hwnd
EnumFunc = 0
Else
EnumFunc = 1
End If
End If
End Function 拦截ComboBox的mouse右键 的代码
楼上的代码测试OK,通理我可以拦截ComboBox的各种消息。
楼上的代码在测试本程序中的ComboxBox很正常。
但是如果我要拦截其它应用程序(不知道何种语言,通过Spy++可以确定上面有一个ComboBox)的ComboBox的消息就不行了,SetWindowLong和GetWindowLong全部失败,返回0。
具体如下:
FindEditInCombo稍作修改:
Public Function FindEditInCombo2(ctl As long) As Long
Call EnumChildWindows(ctl, AddressOf EnumFunc, 0)
FindEditInCombo = hEditWnd
End Functionhwnd5 = FindEditInCombo(Combo1)改为 hwnd5 = FindEditInCombo2(handle)
其中handle是通过Spy++查到的外部应用程序中ComboBox的句柄。为何不行?是不是不能拦截外部消息?听说要写在DLL里面什么的,请楼上的高手再指点一下,小弟万分感激。
Public Function FindEditInCombo2(ctl As long) As Long
Call EnumChildWindows(ctl, AddressOf EnumFunc, 0)
FindEditInCombo2 = hEditWnd
End Function
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Function PtInRect Lib "user32" (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lparam As Any) As Long
Private Const HC_ACTION = 0
Private Const WH_MOUSE_LL As Long = 14
Private Const WM_MOUSEMOVE = &H200
Private Const WM_MOUSELEAVE = &H2A3
Public Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End TypePrivate Type POINTAPI
x As Long
y As Long
End Type
Private Type MSLLHOOKSTRUCT
pt As POINTAPI
mouseData As Long
Flags As Long
time As Long
dwExtraInfo As Long
End Type
Public hHook As Long
Public hRT As RECT
Public Sub EnableHook(hRect As RECT)
hRT = hRect
If hHook = 0 Then
hHook = SetWindowsHookEx(WH_MOUSE_LL, AddressOf HookProc, App.hInstance, 0)
End If
End Sub
Public Sub FreeHook()
If hHook <> 0 Then
Call UnhookWindowsHookEx(hHook)
hHook = 0
End If
End SubPublic Function HookProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lparam As Long) As Long
Dim typMHS As MSLLHOOKSTRUCT, pt As POINTAPI
If nCode < 0 Then
HookProc = CallNextHookEx(hHook, nCode, wParam, lparam)
Exit Function
End If
If wParam = 513 Then
Call CopyMemory(typMHS, ByVal lparam, LenB(typMHS))
pt = typMHS.pt
If PtInRect(hRT, pt.x, pt.y) <> 0 Then
Form1.Print "在指定范围内点击"
HookProc = 1 '取消原本要完成的动作
Else
Form1.Caption = "mouse Cursor at " + CStr(pt.x) + "," + CStr(pt.y)
HookProc = 0 '令待完成的动作继续完成
End If End IfEnd Function
窗体代码
Option Explicit
Const HWND_TOPMOST = -1
Const HWND_NOTOPMOST = -2
Const SWP_NOSIZE = &H1
Const SWP_NOMOVE = &H2
Const SWP_NOACTIVATE = &H10
Const SWP_SHOWWINDOW = &H40
Private Declare Sub SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long)Private Sub Form_Activate()
'设置窗口为TOPMOST窗口,目的是便于观察
SetWindowPos Me.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE Or SWP_SHOWWINDOW Or SWP_NOMOVE Or SWP_NOSIZE
End Sub
Private Sub Form_Load()
Dim RT As RECT
With RT
.Left = 0
.Right = 400
.Top = 0
.Bottom = 300
End With
EnableHook RT
End SubPrivate Sub Form_Unload(Cancel As Integer)
FreeHook
End Sub这样就可以监控所有在范围 400.300内的鼠标左键点击
你可以获取你所要控制的控件的位置 然后监视在这个范围内的点击
SetWindowsHookEx(WH_MOUSE,MouseProc,0,GetCurrentThreadId())
GetCurrentThreadId()修改为你的程序的线程id就可以了
vb是不能做系统级的钩子的,要么lz就用c++写个dll给vb调用
Private Declare Function SendMessageByString& Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String)
Public Const WM_GETTEXT = &HD以下的是在按钮上的
SendMessageByString& 句柄, WM_GETTEXT, 0, 0应该是可以的,我都可以拿到它的信息!记得比分
我要监控的Combo1,其Text的改变不是通过键盘输入的,所以不能用键盘钩子来实现。
其Text是Combo1所在进程内部改写的,我就是要捕捉那改写的一刹那。
好像有点难度。
myjian(小马--现在已经80KG 只有跨进程子类化......
说具体点怎么监视控吧?