以前就提过的问题,现在还没有解决
问题是这样的,我有一个窗体专门用来截留屏幕某一区域的鼠标操作,并且如同痕迹显示一样在窗体上绘制鼠标操作相应的数据记录,然后将鼠标消息继续传给Z轴上在窗体之下的其它窗口。这样的窗体我可以简单的令其透明来显示下层窗口,绘制的部分也很简单,但是如何简洁明了的将鼠标消息分析并传递给下层窗体应该怎么写?
最主要的是,考虑到VB消息截流的效率,这样的代码应该越简单越好,用FindWindow然后按照鼠标位置逐一排除窗口的方法会带来很大的问题。本人对SubClass不熟,没什么思路,所以向各位高手请教,小弟在此先谢谢各位了。
问题是这样的,我有一个窗体专门用来截留屏幕某一区域的鼠标操作,并且如同痕迹显示一样在窗体上绘制鼠标操作相应的数据记录,然后将鼠标消息继续传给Z轴上在窗体之下的其它窗口。这样的窗体我可以简单的令其透明来显示下层窗口,绘制的部分也很简单,但是如何简洁明了的将鼠标消息分析并传递给下层窗体应该怎么写?
最主要的是,考虑到VB消息截流的效率,这样的代码应该越简单越好,用FindWindow然后按照鼠标位置逐一排除窗口的方法会带来很大的问题。本人对SubClass不熟,没什么思路,所以向各位高手请教,小弟在此先谢谢各位了。
網上直接搜索就有含Source的.
我想的的方法是WindowFromPoint加SendMassage应该可以搞定, 不过没试过,LZ再研究看看
或者请您谈谈如何不用SubClass?谢谢了!
//然后将鼠标消息继续传给Z轴上在窗体之下的其它窗口
这个我不知道你的目的何在,“其它窗口”具体是什么
PS:个人感觉,你的问题用钩子解决更合理一些
但这样做,还是会闪动,所以用Enum才是合理选择,效率也不会低,而且稳定。SubClass不能跨进程,进程外的窗体消息拦截要用Hook,但VB做有些难,更重要的是我实在想不出用钩子的目的,钩哪个窗体呢?钩住又有什么用呢?只有一点我可以肯定,上钩后效率会更低。这样吧,我先抽空写个Enum的代码试试。
Option Explicit
Private Const DESKTOP_ENUMERATE = &H40&
Private Type POINTAPI
x As Long
y As Long
End TypePrivate Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function IsIconic Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function IsWindowEnabled Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function IsWindowVisible Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function EnumDesktopWindows Lib "user32" (ByVal hDesktop As Long, ByVal lpfn As Long, ByVal lParam As Long) As Long
Private Declare Function OpenDesktop Lib "user32" Alias "OpenDesktopA" (ByVal lpszDesktop As String, ByVal dwFlags As Long, ByVal fInherit As Boolean, ByVal dwDesiredAccess As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function ClientToScreen Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
Private TestPoint As POINTAPIPrivate Function EnumWindowsProc(ByVal hwd As Long, ByVal lp As Long) As Boolean
Dim rec As RECT, s As String
If hwd <> lp Then '排除自己,当然最底层的“Program Manager”可能也需排除,你自己加吧
If IsIconic(hwd) = 0 And IsWindowEnabled(hwd) And IsWindowVisible(hwd) Then
GetWindowRect hwd, rec
If TestPoint.x >= rec.Left And TestPoint.x <= rec.Right And TestPoint.y >= rec.Top And TestPoint.y <= rec.Bottom Then
'这里你可用SendMassge传递鼠标消息,
'我建议最好MouseDown时把它们加入一个数组或集合,这样在MouseMove时可直接使用,MouseUp时清空数组或集合
s = String$(100, " ")
GetWindowText hwd, s, 100
Debug.Print Trim$(s)
End If
End If
End If
EnumWindowsProc = 1
End FunctionPublic Sub FindDownWin(hwnd As Long, x As Long, y As Long)
Dim hDesk As Long, xy(1) As Integer, lp As Long
TestPoint.x = x
TestPoint.y = y
ClientToScreen hwnd, TestPoint
'这种方法不适于9X系统,对于Win9X,你还是用EnumWindows吧
hDesk = OpenDesktop(vbNullString, 0, False, DESKTOP_ENUMERATE)
EnumDesktopWindows hDesk, AddressOf EnumWindowsProc, hwnd
CloseHandle hDesk
End Sub----------------------------------------
窗体中的代码
Option ExplicitPrivate Sub Form_Load()
Me.ScaleMode = 3
End SubPrivate Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
FindDownWin Me.hwnd, CLng(x), CLng(y)
End
关于我为什么要向下传递鼠标消息,可以大致理解为我的窗口就是一片软件滤色膜,“贴”在所有窗口之上,滤色膜显然不会影响鼠标的操作所以需要将鼠标操作向下传递。
至于键盘的输入操作因为我可以令窗口TOPMOST所以丢失焦点的情况不需要在意。to all:
刚刚想到这个问题,用窗口枚举的时候会导致本窗口获得焦点吗?是不是需要采取措施防止焦点的获得?
谢了!