两者从函数结构上看主要区别其实就是返回值不同,SendMessage返回消息被处理后的返回值,而PostMessage则返回消息是否发送成功。
其次,SendMessage是同步的,而PostMessage是异步的。SendMessage会等待消息被处理完成之后再返回,PostMessage则会将消息放入处理队列中直接返回。另外,再不同线程操作时,最好用PostThreadMessage代替。
Windows提供的一个模拟键盘API函数,该函数能触发一个按键事件,也就是说同样会产生一个WM_KEYDOWN或WM_KEYUP消息。
需要 using System.Windows.Forms;功能是 将一个或多个按键消息发送到活动窗口,就如同在键盘上进行输入一样。其中一些字符都有特殊意义,
语法:SendKeys.Send(string keys);SendKeys.SendWait(string keys);
首先,我们来看一下直接点击 Ctrl + S 在 Spy++ 上显示出的命令:
下面介绍几个需要用到的函数,代码在下面已贴出。
parm1:接收窗口的句柄
parm2:发送的消息,根据不同的需求和不同的对象,需要填入不同的实参。我们在模拟用户操作时,需要填入 WindowMessage参数(下面代码中有给出)。
parm3:附加的消息信息,对parm2的补充。这边我们应该填入 键盘操作的虚拟键值(键值表下面有给出)。
parm4:附加的消息信息,对parm2的补充。此处我们需要填入一个32位的uint参数,具体的定义如下:
0~15位:表示发送的次数,一般就是1次
16~23位:表示键盘的操作的扫描码
24位:表示是左ALT、CTRL还是右ALT、CTRL(通常为0)
25~28位:保留
29位:决定了 消息内容中 fAltDown 的值为1还是0(不知道有什么用…)
30位:表示上一个键的状态KEY DOWN or UP,1为发送前的DOWN状态,0为UP
31位:0为按下,1为释放
上图是通过 SendMessage 函数发送相应数据得到的结果。经过对比,spy++确实捕捉到了Ctrl + S 的键盘事件,然而,现象却是,钩子函数没有捕捉到… 很尴尬。(希望有懂的同志能交流下)
parm1:键盘虚拟键值
parm2:键盘键值扫描码(试过之后发现,填0也可以,根本不需要这个值)
parm3:状态参数:非 KEYEVENTF_KEYUP 即 按下
parm3:扩展信息(0)
上图为 keybd_event 的结果,可以看到,钩子函数捕捉到了!然鹅,spy++捕捉到的键盘事件却和真实点击出现的事件不完全相同。也就是,用了奇怪的方法却完成了需求… 依旧尴尬。
FindWindow : 获取某窗口句柄,parm1:窗口类名(null),parm2:窗口关键字
SetForegroundWindow :设置某窗口为当前活动窗口
GetForegroundWindow : 获取当前活动窗口
ShowWindow :设置窗口,parm2:0:close, 1:normal, 2:min, 3:max
using System.Runtime.InteropServices;
class Program
{
[DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
private extern static IntPtr FindWindow(string classname, string captionName);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
[DllImport("user32.dll", EntryPoint = "PostMessage")]
public static extern bool PostMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("user32.dll")] private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
#region 预定义参数
#endregion
// 键盘虚拟键值
private const int VK_CONTROL = 0X11;
private const int VK_MENU = 0X12;
private const int VK_S = 0X53; // 'S'
private const int VK_F4 = 0X73;
private const int KEYEVENTF_EXTENDEDKEY = 0x1;
private const int KEYEVENTF_KEYUP = 0x2;
// WindowMessage 参数
private const int WM_KEYDOWN = 0X100;
private const int WM_KEYUP = 0X101;
private const int WM_SYSCHAR = 0X106;
private const int WM_SYSKEYUP = 0X105;
private const int WM_SYSKEYDOWN = 0X104;
private const int WM_CHAR = 0X102;
private const int WM_DOWN = 0X0028;
private const int WM_ENTER = 0X000D;
private const int WM_CLOSE = 0X0010;
private const int WM_QUIT = 0X0012;
// keybd_event 状态参数
public const int WM_SYSCOMMAND = 0x111;
public const int SC_MINIMIZE = 0xF020;
public const int SC_MAXIMIZE = 0xF030;
static void SendMsg(IntPtr hwnd)
{
//hwnd = FindWindowEx(hwnd, IntPtr.Zero, "ToolbarWindow32", ""); // 获取子面板的窗口句柄
Console.WriteLine("进程句柄: " + hwnd);
Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYDOWN, VK_CONTROL, 0x001D0001)); // Ctrl + S
Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYDOWN, VK_S, 0x001F0001));
Console.WriteLine("Message : " + PostMessage(hwnd, WM_CHAR, 0x13, 0x001F0001));
Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYUP, VK_CONTROL, 0xC01D0001));
Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYUP, VK_S, 0xC01F0001));
//Console.WriteLine("Message : " + PostMessage(hwnd, WM_SYSKEYDOWN, VK_MENU, 0x20380001)); // Alt + F4
//Console.WriteLine("Message : " + PostMessage(hwnd, WM_SYSKEYDOWN, VK_F4, 0x203E0001));
//Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYUP, VK_MENU, 0xE0380001));
//Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYUP, VK_F4, 0xE03E0001));
}
static void Keybd_event_Msg()
{
keybd_event(VK_CONTROL, 0, 0, 0); // Ctrl + S
keybd_event(VK_S, 0, 0, 0);
keybd_event(VK_S, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
//keybd_event(VK_MENU, 0, 0, 0); // Alt + F4
//keybd_event(VK_F4, 0, 0, 0);
//keybd_event(VK_F4, 0, KEYEVENTF_KEYUP, 0);
//keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
}
static void Main()
{
IntPtr mwh1 = IntPtr.Zero;
while (mwh1 == IntPtr.Zero)
{
Console.WriteLine("寻找窗口中...");
mwh1 = FindWindow(null, "HookReceiverWpf");
Thread.Sleep(1000);
}
//SendMsg(mwh1);
SetForegroundWindow(mwh1);
Keybd_event_Msg();
//System.Windows.Forms.SendKeys
Console.ReadKey();
}
}
虚拟键 | 十六进制值 | 十进制值 | 相应键盘或鼠标键 |
---|---|---|---|
VK_LBUTTON | 1 | 1 | 鼠标左键 |
VK_RBUTTON | 2 | 2 | 鼠标右键 |
VK_CANCEL | 3 | 3 | Ctrl-Break键 |
VK_MBUTTON | 4 | 4 | 鼠标中键 |
VK_BACK | 8 | 8 | Backspace键 |
VK_TAB | 9 | 9 | Tab键 |
VK_CLEAR | 0C | 12 | Clear键 |
VK_RETURN | 0D | 13 | Enter键 |
VK_SHIFT | 10 | 16 | Shift键 |
VK_CONTROL | 11 | 17 | Ctrl键 |
VK_MENU | 12 | 18 | Alt键 |
VK_PAUSE | 13 | 19 | Pause键 |
VK_CAPITAL | 14 | 20 | Caps Lock键 |
VK_ESCAPE | 1B | 27 | Esc键 |
VK_SPACE | 20 | 32 | Space键 |
VK_PRIOR | 21 | 33 | Page Up键 |
VK_NEXT | 22 | 34 | Page Down键 |
VK_END | 23 | 35 | End键 |
VK_HOME | 24 | 36 | Home键 |
VK_LEFT | 25 | 37 | ←键 |
VK_UP | 26 | 38 | ↑键 |
VK_RIGHT | 27 | 39 | →键 |
VK_DOWN | 28 | 40 | ↓键 |
VK_SELECT | 29 | 41 | Select键 |
VK_PRINT | 2A | 42 | Print键 |
VK_EXECUTE | 2B | 43 | Execute键 |
VK_SNAPSHOT | 2C | 44 | Print Screen键 |
VK_INSERT | 2D | 45 | Ins键 |
VK_DELETE | 2E | 46 | Del键 |
VK_HELP | 2F | 47 | Help键 |
VK_0 | 30 | 48 | 0键 |
VK_1 | 31 | 49 | 1键 |
VK_2 | 32 | 50 | 2键 |
VK_3 | 33 | 51 | 3键 |
VK_4 | 34 | 52 | 4键 |
VK_5 | 35 | 53 | 5键 |
VK_6 | 36 | 54 | 6键 |
VK_7 | 37 | 55 | 7键 |
VK_8 | 38 | 56 | 8键 |
VK_9 | 39 | 57 | 9键 |
VK_A | 41 | 65 | A键 |
VK_B | 42 | 66 | B键 |
VK_C | 43 | 67 | C键 |
VK_D | 44 | 68 | D键 |
VK_E | 45 | 69 | E键 |
VK_F | 46 | 70 | F键 |
VK_G | 47 | 71 | G键 |
VK_H | 48 | 72 | H键 |
VK_I | 49 | 73 | I键 |
VK_J | 4A | 74 | J键 |
VK_K | 4B | 75 | K键 |
VK_L | 4C | 76 | L键 |
VK_M | 4D | 77 | M键 |
VK_N | 4E | 78 | N键 |
VK_O | 4F | 79 | O键 |
VK_P | 50 | 80 | P键 |
VK_Q | 51 | 81 | Q键 |
VK_R | 52 | 82 | R键 |
VK_S | 53 | 83 | S键 |
VK_T | 54 | 84 | T键 |
VK_U | 55 | 85 | U键 |
VK_V | 56 | 86 | V键 |
VK_W | 57 | 87 | W键 |
VK_X | 58 | 88 | X键 |
VK_Y | 59 | 89 | Y键 |
VK_Z | 5A | 90 | Z键 |
VK_LWIN | 5B | 91 | 左Windows键 |
VK_RWIN | 5C | 92 | 右Windows键 |
VK_APPS | 5D | 93 | 应用程序键 |
VK_SLEEP | 5F | 95 | 休眠键 |
VK_NUMPAD0 | 60 | 96 | 小数字键盘0键 |
VK_NUMPAD1 | 61 | 97 | 小数字键盘1键 |
VK_NUMPAD2 | 62 | 98 | 小数字键盘2键 |
VK_NUMPAD3 | 63 | 99 | 小数字键盘3键 |
VK_NUMPAD4 | 64 | 100 | 小数字键盘4键 |
VK_NUMPAD5 | 65 | 101 | 小数字键盘5键 |
VK_NUMPAD6 | 66 | 102 | 小数字键盘6键 |
VK_NUMPAD7 | 67 | 103 | 小数字键盘7键 |
VK_NUMPAD8 | 68 | 104 | 小数字键盘8键 |
VK_NUMPAD9 | 69 | 105 | 小数字键盘9键 |
VK_MULTIPLY | 6A | 106 | 乘号键 |
VK_ADD | 6B | 107 | 加号键 |
VK_SEPARATOR | 6C | 108 | 分割键 |
VK_SUBSTRACT | 6D | 109 | 减号键 |
VK_DECIMAL | 6E | 110 | 小数点键 |
VK_DIVIDE | 6F | 111 | 除号键 |
VK_F1 | 70 | 12 | F1键 |
VK_F2 | 71 | 113 | F2键 |
VK_F3 | 72 | 114 | F3键 |
VK_F4 | 73 | 115 | F4键 |
VK_F5 | 74 | 116 | F5键 |
VK_F6 | 75 | 117 | F6键 |
VK_F7 | 76 | 118 | F7键 |
VK_F8 | 77 | 119 | F8键 |
VK_F9 | 78 | 120 | F9键 |
VK_F10 | 79 | 121 | F10键 |
VK_F11 | 7A | 122 | F11键 |
VK_F12 | 7B | 123 | F12键 |
VK_F13 | 7C | 124 | F13键 |
VK_F14 | 7D | 125 | F14键 |
VK_F15 | 7E | 126 | F15键 |
VK_F16 | 7F | 127 | F16键 |
VK_F17 | 80 | 128 | F17键 |
VK_F18 | 81 | 129 | F18键 |
VK_F19 | 82 | 130 | F19键 |
VK_F20 | 83 | 131 | F20键 |
VK_F21 | 84 | 132 | F21键 |
VK_F22 | 85 | 133 | F22键 |
VK_F23 | 86 | 134 | F23键 |
VK_F24 | 87 | 135 | F24键 |
VK_NUMLOCK | 90 | 144 | Num Lock键 |
VK_SCROLL | 91 | 45 | Scroll Lock键 |
VK_LSHIFT | A0 | 160 | 左Shift键 |
VK_RSHIFT | A1 | 161 | 右Shift键 |
VK_LCONTROL | A2 | 162 | 左Ctrl键 |
VK_RCONTROL | A3 | 163 | 右Ctrl键 |
VK_LMENU | A4 | 164 | 左Alt键 |
VK_RMENU | A5 | 165 | 右Alt键 |
最后附上 Spy++ 的链接: https://pan.baidu.com/s/1D3E4N3mRRVwW24i1PonbnA 提取码:azga