PostMessage发送消息遇WM_CHAR额外生成及wParam值错误问题排查
问题解答
1. 修复wParam值错误的问题
核心问题是对键盘消息的参数定义理解错误,且WM_KEYUP的参数设置不正确:
- 对于
WM_KEYDOWN/WM_KEYUP,wParam是虚拟键码(例如你要发送的空格键对应0x20),lParam才是包含重复计数、扫描码、按键状态等信息的复合参数(即你写的0x00390001)。你描述中wParam显示为0,大概率是WindowsMessagesFlags.WM_KEYDOWN的枚举值定义错误,需确认其值为0x0100(WM_KEYDOWN标准值),WM_KEYUP为0x0101。 - 另外,
WM_KEYUP的lParam最高位(位31)必须设为1,表示按键已释放,正确的lParam应为0xC0390001(将原WM_KEYDOWN的lParam最高位设1)。
修正后的调用代码:
PostMessage(window, 0x0100, (UIntPtr)0x20, (UIntPtr)0x00390001); // WM_KEYDOWN Thread.Sleep(15); PostMessage(window, 0x0101, (UIntPtr)0x20, (UIntPtr)0xC0390001); // WM_KEYUP
2. 阻止WM_CHAR消息生成
WM_CHAR是系统通过TranslateMessage函数自动生成的,当目标窗口的消息循环调用该函数时,收到WM_KEYDOWN就会触发WM_CHAR。要避免这种情况,优先使用Windows推荐的SendInput函数模拟输入——它直接模拟硬件级按键流程,不会触发额外的WM_CHAR(或可精准控制输入行为)。
SendInput的示例实现:
using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] public struct INPUT { public uint type; public InputUnion u; } [StructLayout(LayoutKind.Explicit)] public struct InputUnion { [FieldOffset(0)] public KEYBDINPUT ki; } [StructLayout(LayoutKind.Sequential)] public struct KEYBDINPUT { public ushort wVk; public ushort wScan; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; } [DllImport("user32.dll", SetLastError = true)] public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); // 模拟空格键按下+松开 var inputSequence = new INPUT[2]; // 按下空格键 inputSequence[0].type = 1; // 标记为键盘输入 inputSequence[0].u.ki.wVk = 0x20; inputSequence[0].u.ki.dwFlags = 0; // 松开空格键 inputSequence[1].type = 1; inputSequence[1].u.ki.wVk = 0x20; inputSequence[1].u.ki.dwFlags = 0x0002; // KEYEVENTF_KEYUP SendInput(2, inputSequence, Marshal.SizeOf(typeof(INPUT)));
如果必须使用PostMessage,只有目标窗口的消息循环不调用TranslateMessage才能避免WM_CHAR,但这通常无法由外部控制,因此SendInput是更可靠的方案。
内容的提问来源于stack exchange,提问作者steam3d
相关产品推荐
相关产品推荐

