捕获窗口消息然后触发代码

时间:2014-05-19 15:49:53

标签: c# wpf .net-4.5

我有一个窗口代码,在其中,我订阅了一个接收系统消息的函数:

... 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,而无需将消息重新发送给自己?

1 个答案:

答案 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早到或晚到。)