Cas*_*roy 1 c# winapi bit-manipulation intptr
目前,我正在开发一个简单的类库,以在各种博客文章和SO 答案的帮助下处理全局热键。
考虑一下我整理的这段完整的代码。
protected override void WndProc(ref Message m)
{
const int WM_HOTKEY = 0x0312;
if (m.Msg == WM_HOTKEY)
{
var modifier = (int) m.LParam & 0xFFFF;
var key = ((int) m.LParam & 0xFFFF);
}
base.WndProc(ref m);
}
Run Code Online (Sandbox Code Playgroud)
我真的不明白,想解释一下位掩码在这里是如何工作的。我对如何应用按位运算符有合理的理解,但我不明白为什么在这里应用这个特定的位掩码。
此外,我正在努力理解 的目的IntPtr。为什么是LParam并且IntPtr在这种情况下?谢谢。
的文档WM_HOTKEY说包含LPARAM两个 16 位字段。高字(高 16 位)具有按下的按键的 VK,低字(低 16 位)具有指定的修饰符。
LPARAM & 0xffff将获取低 16 位,LPARAM >> 16并将获取高 16 位。
LPARAM & 0xffff之所以有效,是因为 32 位 LPARAM 如下所示:
V bit 31 V bit 0\n HIGH WORD LOW WORD\n0y vvvv vvvv vvvv vvvv mmmm mmmm mmmm mmmm where v is the vk, and m is the modifier \n0y 0000 0000 0000 0000 1111 1111 1111 1111 == 0x0000ffff\n========================================== Bitwise and\n0y 0000 0000 0000 0000 mmmm mmmm mmmm mmmm Just left with the modifier bits\nRun Code Online (Sandbox Code Playgroud)\n\nLPARAM >> 16工作原理是将位向右移动 16 个位置
V bit 31 V bit 0\n HIGH WORD LOW WORD\n0y vvvv vvvv vvvv vvvv mmmm mmmm mmmm mmmm where v is the vk, and m is the modifier \n0y 0vvv vvvv vvvv vvvv vmmm mmmm mmmm mmmm right shifted once (>> 1)\n0y 00vv vvvv vvvv vvvv vvmm mmmm mmmm mmmm right shifted twice (>> 2)\n...\n0y 0000 0000 0000 0000 vvvv vvvv vvvv vvvv right shifted sixteen times (>> 16)\nRun Code Online (Sandbox Code Playgroud)\n\nLPARAM被定义为指针的大小,因此它将映射到IntPtr托管代码中。由于我们只使用 LPARAM 的低 32 位,因此我们需要砍掉高 32 位。我们可以强制转换 toint来执行此操作,但如果您运行checked算术,则会产生OverflowException. 相反,我们将 转换IntPtr为 a long(在 32 位机器上将进行零填充),然后转换为 a int(将截断)。
如果我们不将 的大小调整IntPtr为 a Int32,如果应用程序要发送设置为 的结果的高位消息,则可能会出现异常lparam >> 16。
IntPtr lparam = /* comes from WndProc */;\nInt32 lparam32 = unchecked((int)(long)lparam);\n\nInt16 lowWord = lparam32 & 0xffff;\nInt16 highWord = lparam32 >> 16;\nRun Code Online (Sandbox Code Playgroud)\n\n话虽如此,这里是 C# 中热键侦听器的完整实现,我不记得在哪里找到的。如果有人对此有出处,请告诉我,或编辑这篇文章以列出原作者。
\n\nusing System;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Windows.Forms;\n\npublic sealed class KeyboardHook : IDisposable\n{\n private int _currentId;\n private Window _window;\n\n public event EventHandler<KeyPressedEventArgs> KeyPressed;\n\n public KeyboardHook()\n {\n EventHandler<KeyPressedEventArgs> handler = null;\n this._window = new Window();\n if (handler == null)\n {\n handler = delegate (object sender, KeyPressedEventArgs args) {\n if (this.KeyPressed != null)\n {\n this.KeyPressed(this, args);\n }\n };\n }\n this._window.KeyPressed += handler;\n }\n\n public void Dispose()\n {\n for (int i = this._currentId; i > 0; i--)\n {\n UnregisterHotKey(this._window.Handle, i);\n }\n this._window.Dispose();\n }\n\n public void RegisterHotKey(ModifierKeys modifier, Keys key)\n {\n this._currentId++;\n if (!RegisterHotKey(this._window.Handle, this._currentId, (uint) modifier, (uint) key))\n {\n throw new InvalidOperationException("Couldn\xe2\x80\x99t register the hot key.");\n }\n }\n\n [DllImport("user32.dll")]\n private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);\n [DllImport("user32.dll")]\n private static extern bool UnregisterHotKey(IntPtr hWnd, int id);\n\n private class Window : NativeWindow, IDisposable\n {\n private static int WM_HOTKEY = 0x312;\n\n public event EventHandler<KeyPressedEventArgs> KeyPressed;\n\n public Window()\n {\n this.CreateHandle(new CreateParams());\n }\n\n public void Dispose()\n {\n this.DestroyHandle();\n }\n\n protected override void WndProc(ref Message m)\n {\n base.WndProc(ref m);\n if (m.Msg == WM_HOTKEY)\n {\n Keys key = ((Keys) (((int) m.LParam) >> 0x10)) & Keys.KeyCode;\n ModifierKeys modifier = ((ModifierKeys) ((int) m.LParam)) & ((ModifierKeys) 0xffff);\n if (this.KeyPressed != null)\n {\n this.KeyPressed(this, new KeyPressedEventArgs(modifier, key));\n }\n }\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n