Windows 10系统下SendMessage与PostMessage按键模拟功能失效咨询
Windows 10 下SendMessage模拟按键失效解决方案
核心原因
Windows 10相比Windows 8大幅增强了输入安全限制,主要涉及UIPI(用户界面特权隔离)规则收紧、非信任进程注入窗口消息拦截、以及UWP应用输入处理机制变更,这些都会导致原有SendMessage模拟按键方案失效。
可行解决建议
权限匹配校验
你的程序和目标程序必须运行在相同权限等级:要么都不使用管理员权限运行,要么都以管理员身份运行。如果目标程序以管理员权限启动,而你的程序未提权,UIPI会直接拦截输入类消息且不会抛出异常,可通过修改项目清单配置
requireAdministrator启动权限验证该问题。改用SendInput API模拟硬件输入
SendInput直接向系统全局输入队列插入输入事件,属于硬件级模拟,绕过绝大多数窗口消息拦截限制,兼容绝大多数场景,C#实现示例如下:
首先引入API声明:[DllImport("user32.dll", SetLastError = true)] public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); [StructLayout(LayoutKind.Sequential)] public struct INPUT { public uint type; public InputUnion U; public static int Size => Marshal.SizeOf(typeof(INPUT)); } [StructLayout(LayoutKind.Explicit)] public struct InputUnion { [FieldOffset(0)] public MOUSEINPUT mi; [FieldOffset(0)] public KEYBDINPUT ki; [FieldOffset(0)] public HARDWAREINPUT hi; } [StructLayout(LayoutKind.Sequential)] public struct KEYBDINPUT { public ushort wVk; public ushort wScan; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; } public const uint INPUT_KEYBOARD = 1; public const uint KEYEVENTF_KEYUP = 0x0002; [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);按键功能实现:
private void KeyPress(IntPtr targetHandle, ushort vk) { // 先激活目标窗口确保输入定向正确 SetForegroundWindow(targetHandle); // 构造按键按下事件 INPUT keyDown = new INPUT { type = INPUT_KEYBOARD, U = new InputUnion { ki = new KEYBDINPUT { wVk = vk } } }; // 构造按键抬起事件 INPUT keyUp = new INPUT { type = INPUT_KEYBOARD, U = new InputUnion { ki = new KEYBDINPUT { wVk = vk, dwFlags = KEYEVENTF_KEYUP } } }; // 提交输入事件 SendInput(2, new[] { keyDown, keyUp }, INPUT.Size); }修正原有SendMessage的参数格式
你原有代码中
lParam参数传IntPtr.Zero不符合系统消息规范,Windows 10对消息参数校验更严格,可修正参数后重试:[DllImport("user32.dll")] public static extern uint MapVirtualKey(uint uCode, uint uMapType); private void KeyPress(IntPtr handle, IntPtr vk) { try { if (handle == IntPtr.Zero) return; uint scanCode = MapVirtualKey((uint)vk, 0); // 构造WM_KEYDOWN合法lParam IntPtr downLParam = (IntPtr)(0x00000001 | (scanCode << 16)); SendMessage(handle, WM.KEYDOWN, vk, downLParam); // 构造WM_KEYUP合法lParam IntPtr upLParam = (IntPtr)(0xC0000001 | (scanCode << 16)); SendMessage(handle, WM.KEYUP, vk, upLParam); } catch (Exception ex) { // 补充日志排查错误 } }UWP目标适配
如果模拟目标为UWP应用,窗口消息方案基本失效,优先使用SendInput,或者调用微软官方的
Windows.UI.Input.Preview.Injection输入注入API,兼容效果最好。
内容的提问来源于stack exchange,提问作者Yakov Vorontsov
相关产品推荐
相关产品推荐

