我有一个窗口代码,在其中,我订阅了一个接收系统消息的函数:
... IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
在这个功能中,当我看到我正在等待的消息时,我会触发我的课程
... IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
...some code checking the type of the mesage, etc....
new MyClass(); //Trigger my class
}
如果我这样做,那么我得到这个错误" RPC_E_CANTCALLOUT_ININPUTSYNCCALL"。经过一些研究,如果我理解正确,它不会允许我运行MyClass或类似的代码,因为我试图在系统尚未完成所有消息或类似问题时执行它
因此,为了绕过这个问题,我将消息重新发送给自己:
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
...some code checking the type of the mesage, etc....
if (msg != 0xD903) //If msg is not 55555 this message is not a repost and therefore repost it
{
var devType = Marshal.ReadInt32(lParam, 4);
Debug.WriteLine(devType); //This correctly prints out "2" which i get from lParam
PostMessage(hwnd, 55555, wParam, lParam); //repost message
}
else //If the msg is 55555 this message is my repost and I can execute MyClass with no problems
{
var devType = Marshal.ReadInt32(lParam, 4);
Debug.WriteLine(devType); //This should also print out "2", since I am merely reposting the lParam, without changing it in any way, but instead it prints "0"
new MyClass(); //Trigger my class
}
}
要解决我的问题,我需要知道:
为什么我重新发布消息时devType为0?
或
是否有一些(简单)方法可以在我收到系统消息时直接触发MyClass,而无需将消息重新发送给自己?
答案 0 :(得分:1)
关于你的LParam为0 ...你正在将IntPtr视为4的大小,如果你的目标AnyCpu和64位操作系统不是这样的话。因此,如果它的大小实际上是8,并且它存储在Little Endian的内存中(它在windows中),则读取4将获得前4个字节,如果值为0将为0小于4字节的最大值。在Little Endian中,值从右到左存储(最高地址到最小地址)。因此,前4个字节中没有任何内容,并且您没有读取最后4个字节,因为您假设IntPtr是4个字节。
尝试使用
Marshal.ReadInt32(lParam,lParam.Size)
IntPtr.Size将在32位运行时返回4,在64位运行时返回8(为您管理该稀释)。
至于其余部分,
另外请记住,如果你想做一个全局挂钩,
您可以在MSG处理程序上使用.Net进行的唯一全局挂钩,例如SetWindowsHookEx," WH_KEYBOARD_LL低级别挂钩和WH_MOUSE_LL"。
现在你可以很好地挂钩自己的流程,但是你无法在.Net中全局挂钩其他流程。
如果您正在挂钩自己的流程,为什么不在表单类上覆盖WndProc,那么您不需要DllImport任何东西,它将以正确的顺序(例如,您赢了& #39; t早到或晚到。)