简体   繁体   English

如何在没有任何内容的情况下拦截来自HwndSource的WndProc消息

[英]How to intercept WndProc messages from a HwndSource without any content

I'm trying to communicate with a native library that uses an HWND to pass messages back to the caller as follows: 我正在尝试与使用HWND将消息传递回调用方的本机库进行通信,如下所示:

private void Example()
{
    using (
        var hwnd = new HwndSource(
            new HwndSourceParameters("I sense a disturbance in the force...") {HwndSourceHook = WndProc}
            )
        )
    {
        //send hwnd.handle to native library
        while (true) { }
    }
}

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool ishandled)
{
    ishandled = false;
    Console.WriteLine("Intercepted message: 0x{0:X}", msg);
    return IntPtr.Zero;
}

Even when the call the the native library is omitted , I only ever receive the following messages (in order): 即使省略了对本机库的调用 ,我也只会(按顺序)收到以下消息:

  1. 0x0001: WM_CREATE 0x0001: WM_CREATE
  2. 0x0018: WM_SHOWWINDOW 0x0018: WM_SHOWWINDOW
  3. 0x0046: WM_WINDOWPOSCHANGING 0x0046: WM_WINDOWPOSCHANGING
  4. 0x0046: WM_WINDOWPOSCHANGING 0x0046: WM_WINDOWPOSCHANGING
  5. 0x001C: WM_ACTIVATEAPP 0x001C: WM_ACTIVATEAPP
  6. 0x0086: WM_NCACTIVATE 0x0086: WM_NCACTIVATE
  7. 0x007F: WM_GETICON 0x007F: WM_GETICON
  8. 0x007F: WM_GETICON 0x007F: WM_GETICON
  9. 0x007F: WM_GETICON 0x007F: WM_GETICON
  10. 0x0006: WM_ACTIVATE 0x0006: WM_ACTIVATE
  11. 0x0281: WM_IME_SETCONTEXT 0x0281: WM_IME_SETCONTEXT
  12. 0x0282: WM_IME_NOTIFY 0x0282: WM_IME_NOTIFY
  13. 0x0007: WM_SETFOCUS 0x0007: WM_SETFOCUS
  14. 0x0085: WM_NCPAINT 0x0085: WM_NCPAINT
  15. 0x0014: WM_ERASEBKGND 0x0014: WM_ERASEBKGND
  16. 0x0047: WM_WINDOWPOSCHANGED 0x0047: WM_WINDOWPOSCHANGED
  17. 0x0083: WM_NCCALCSIZE WM_NCCALCSIZEWM_NCCALCSIZE
  18. 0x0085: WM_NCPAINT 0x0085: WM_NCPAINT
  19. 0x0014: WM_ERASEBKGND 0x0014: WM_ERASEBKGND
  20. 0x0005: WM_SIZE 0x0005: WM_SIZE
  21. 0x0003: WM_MOVE 0x0003: WM_MOVE
  22. 0x000D: WM_GETTEXT 0x000D: WM_GETTEXT

After this I can drag the window corresponding to the HwndSource around but am unable to resize or close it. 此后,我可以拖动与HwndSource对应的窗口,但是无法调整大小或关闭它。 Furthermore the operating system claims that this window is not responding. 此外,操作系统声称该窗口没有响应。

Why does this window stop responding and how can I continue to intercept messages? 为什么此窗口停止响应,如何继续拦截消息?

I think that when you try to retrieve the next message from the windows queue, it freezes your original thread that's waiting for the response from WndProc . 我认为,当您尝试从Windows队列中检索下一条消息时,它将冻结等待WndProc响应的原始线程。

Try intercepting messages through Application.AddMessageFilter as was done in this other question 尝试像上述其他问题一样通过Application.AddMessageFilter拦截消息

As both @HansPassant and @HassanBoutougha pointed out the issue is with the following segment of code: 正如@HansPassant和@HassanBoutougha指出的那样,问题在于以下代码段:

while (true) { }

While this may look like it's innocently keeping the application alive what it's really doing is preventing the dispatcher from processing messages. 尽管这看起来像是无辜地使应用程序保持活动状态,但实际上它是在阻止调度程序处理消息。 The messages that I was seeing was because they were being called directly from within the thread executing Example() by the HwndSource constructor. 我看到的消息是因为HwndSource构造函数直接从执行Example()的线程中调用了它们。 After construction the application enters the loop and runs around in circles. 构建后,应用程序进入循环并循环运行。 Unfortunately this is the thread that's suppose to be processing the messages! 不幸的是,这是处理消息的线程!

Essentially the correct solution here was to tell the dispatcher to put the current call stack on the back burner and process events until we tell it to stop. 本质上,正确的解决方案是告诉调度程序将当前调用堆栈放到后台处理程序中并处理事件,直到我们告诉它停止为止。

DipatcherFrame frame = new DispatcherFrame();
Dispatcher.PushFrame(frame);

Essentially the call to Dispatcher.PushFrame this tells the dispatcher to suspend execution and continue listening to messages. 本质上,对Dispatcher.PushFrame的调用告诉调度程序暂停执行并继续侦听消息。 At some point in the future if you decide that you want to resume execution where you left of just do the following: 在将来的某个时候,如果您决定要恢复执行,请执行以下操作:

frame.Continue = false;

And that's it! 就是这样! The call to Dispatcher.PushFrame will now return and resume execution 现在,对Dispatcher.PushFrame的调用将返回并恢复执行

Kent Boggart has a great example here: http://kentb.blogspot.ca/2008/04/dispatcher-frames.html Unfortunately Kent's blog is no longer available however a snapshot of the page from Google's cache may be found here . 肯特·博格(Kent Boggart)在这里有一个很好的例子: http ://kentb.blogspot.ca/2008/04/dispatcher-frames.html不幸的是,肯特的博客不再可用,但是可以在此处找到Google缓存中页面的快照。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM