现在的位置: 首页 > 综合 > 正文

使用SendMessage向一个程序传送击键(如:Shift+空格、Ctrl+O)消息,如何实现

2014年01月04日 ⁄ 综合 ⁄ 共 5114字 ⁄ 字号 评论关闭

使用SendMessage向一个程序传送击键(如:Shift+空格、Ctrl+O)消息,如何实现?

请教高手:
我需要在我的程序中向CoolEditPro传送“Shift+空格、Ctrl+O、Left、Right”等按键,使用SendKeys函数会有一些程序切换的问题,所以想使用SendMessage函数,但不知具体参数要怎么设置。
测试:
Public Const WM_KEYDOWN = &H100
Public Const WM_CHAR = &H102

SendMessage Text1.hwnd,WM_CHAR,32,1
测试时发现窗口中的文本框不停地接收到空格,而使程序失去响应,不知是何原因。
VB:如何发送WM_KEYDOWN和WM_KEYUP消息
其实没什么说的,只是最近一段时间问的人比较多,所以写上几句
简单的说,有两个需要注意的地方,一是要用postmessage发送消息,二是这两个消息lparam参数比较复杂,发送消息的时候要构造好lparam参数,下面给出示例代码:
Option Explicit
Private Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Private Sub Command1_Click()
Dim jsb As Long
jsb = FindWindow("notepad", vbNullString)
Dim mhwnd As Long
mhwnd = FindWindowEx(jsb, 0, "edit", vbNullString)
Dim lParam As Long
lParam = makelparam(vbKey5, False)
PostMessage mhwnd, WM_KEYDOWN, vbKey5, lParam
lParam = makelparam(vbKey5, True)
PostMessage mhwnd, WM_KEYUP, vbKey5, lParam
End Sub

Private Function makelparam(ByVal VirtualKey As Long, ByVal flag As Boolean) As Long
Dim s As String
Dim Firstbyte As String 'lparam参数的24-31位
If flag = False Then 'keydown
       Firstbyte = "00"
Else
       Firstbyte = "C0" 'keyup
End If
Dim Scancode As Long
'获得虚拟键扫描码
Scancode = MapVirtualKey(VirtualKey, 0)
Dim Secondbyte As String 'lparam参数的16-23位,即虚拟键扫描码
Secondbyte = Right("00" & Hex(Scancode), 2)
s = Firstbyte & Secondbyte & "0001" '0001为lparam参数的0-15位,即发送次数
makelparam = Val("&H" & s)
End Function

关于向Windows窗口发送Alt组合键的问题2006-10-09 16:54这个真是经典问题啊,在网上找了一下,问的人N多,方法差不多,但就是没有很好解决问题。

之前找到一个能正确发送的code:(Alt+A)

PostMessage(hWnd,WM_SYSKEYDOWN,VK_MENU,0);

PostMessage(hWnd,WM_SYSKEYDOWN,0x41,0);

Sleep(50);

PostMessage(hWnd,WM_SYSKEYUP,0x41,0);

PostMessage(hWnd,WM_SYSKEYUP,VK_MENU,0);

有人解释说,按下组合键的时候系统是发两条消息的

但是看到Win32 SDK,感觉上就发一次就可以了……

偶然间又看到最后一个参数的说明,有所发现!先看WM_SYSKEYDOWN的help

The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when the user holds down the ALT key and then presses another key. It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the active window. The window that receives the message can distinguish between these two contexts by checking the context code in the lKeyData parameter.

WM_SYSKEYDOWN
nVirtKey = (int) wParam; // virtual-key code
lKeyData = lParam;       // key data

Parameters

nVirtKey

Value of wParam. Specifies the virtual-key code of the key being pressed.

lKeyData

Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:

Value Description
0-15 Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key.
16-23 Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24 Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25-28 Reserved; do not use.
29 Specifies the context code. The value is 1 if the ALT key is down while the key is pressed; it is 0 if the WM_SYSKEYDOWN message is posted to the active window because no window has the keyboard focus.
30 Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
31 Specifies the transition state. The value is always 0 for a WM_SYSKEYDOWN message.

之前曾经修改过keyData的16-23位为VK_MENU,第30位参数为1,但没效果

请看位29的说明!!

The value is 1 if the ALT key is down while the key is pressed;

当值为1时表示ALT键被按下!这不正是我需要的吗?于是把29位设置为1,函数调用变成

PostMessage(hWnd,WM_SYSKEYDOWN,0x41,1<<29);

经过测试,发现这个就是Alt+A的效果!!原来这么简单,但为什么很多人弄得那么复杂,我当时查找的时候也是迷惘啊,浪费了N多小时。

类似有个WM_SYSKEYUP,WM_SYSCHAR(这个不知道干什么用)

谢谢weiyi75!
还有一个问题请教:关于获取窗口句柄。
XD本想列出所有的窗口,可以将消息发往指定的窗口。于是使用GetWindow函数列举所有的窗口,把返回的值作为PostMessage的hwnd参数,但发现不行。
XD发现使用Shell函数调用应用程序,所返回的值,与GetWindow返回的值不一样,请问是何原因?谢谢!

Shell返回的是PID(进程标示符)吧
GetWindow是返回句柄
所以返回值是不一样的!

    回到最初的问题,如何向Cool Edit Pro传送“Shift+空格、Left、Right”,以控制Cool Edit Pro进行“暂停/播放、后退、前进”?具体实现步骤为何?
疑问:
1、按weiyi75提供的方法:
Dim jsb As Long
jsb = FindWindow("notepad", vbNullString)
Dim mhwnd As Long
mhwnd = FindWindowEx(jsb, 0, "edit", vbNullString)
这样可以获取记事本文本框窗口句柄,相应地Cool Edit Pro的波形窗口的句柄要如何获取?
2、使用PostMessage函数传送“Shift+空格、Left、Right”这3个击键,具体的参数为何?

再次感谢热心的DX们!

mark一下

我也尝试使用SendKey来做,但是效果不太理想,比如:
AppActivate "XXX.MP3 - Cool Edit Pro" , True
SendKeys "+ ", True   '传送“Shift+空格”给CoolEditPro。
Me.Text1.SetFocus '重获焦点。
这个在Windows2000下运行还可以,但是在一台XP上运行有问题,运行后有时可以有时不行。
另外,如果我的程序使用“Alt+↓”作为向CoolEditPro发送“Shift+空格”的热键,好像也有问题,CoolEditPro好像没收到。可能是因为向CoolEditPro传送“Shift+空格”的同时,因为Alt键被按住,所以CoolEditPro收到的是 “Alt+Shift+空格”,我不确定是不是这个原因。
还有一个问题:不知SendKeys是如何实现的?

网上搜了下,除了能用 PostMessage(hWnd,WM_SYSKEYDOWN, vbKeyA,0) 的方法发送带 Alt 的组合键,其他的带 Ctrl 和 Shift 的组合键似乎没办法 用 PostMessage 或者 SendMessage 发送

原帖由 weiyi75 于 2007-5-18 09:27 发表
关于向Windows窗口发送Alt组合键的问题2006-10-09 16:54这个真是经典问题啊,在网上找了一下,问的人N多,方法差不多,但就是没有很好解决问题。

之前找到一个能正确发送的codeAlt+A)

PostMessage(hWnd,WM_ ...

VBProFan 2008-8-11 11:11 威望 +4 精品文章

【上篇】
【下篇】

抱歉!评论已关闭.