我正在尝试与使用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;
}
即使在省略本机库的调用时,我也只收到以下消息(按顺序):
WM_CREATE
WM_SHOWWINDOW
WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGING
WM_ACTIVATEAPP
WM_NCACTIVATE
WM_GETICON
WM_GETICON
WM_GETICON
WM_ACTIVATE
WM_IME_SETCONTEXT
WM_IME_NOTIFY
WM_SETFOCUS
WM_NCPAINT
WM_ERASEBKGND
WM_WINDOWPOSCHANGED
WM_NCCALCSIZE
WM_NCPAINT
WM_ERASEBKGND
WM_SIZE
WM_MOVE
WM_GETTEXT
在此之后我可以拖动与HwndSource
对应的窗口,但无法调整大小或关闭它。此外,操作系统声称此窗口没有响应。
为什么此窗口停止响应,如何继续拦截消息?
答案 0 :(得分:1)
我认为当您尝试从Windows队列中检索下一条消息时,它会冻结等待WndProc
响应的原始主题。
尝试通过Application.AddMessageFilter
答案 1 :(得分:0)
由于@HansPassant和@HassanBoutougha都指出问题在于以下代码段:
while (true) { }
虽然这可能看起来像是无辜地保持应用程序存活,但它真正做的是阻止调度程序处理消息。我看到的消息是因为它们是在Example()
构造函数执行HwndSource
的线程中直接调用的。构建完成后,应用程序进入循环并绕圈运行。不幸的是,这是假设要处理消息的线程!
基本上,这里的正确解决方案是告诉调度员将当前的调用堆栈置于后台并处理事件,直到我们告诉它停止。
DipatcherFrame frame = new DispatcherFrame();
Dispatcher.PushFrame(frame);
基本上对Dispatcher.PushFrame
的调用告诉调度程序暂停执行并继续监听消息。在将来的某个时候,如果您决定要继续执行,请执行以下操作:
frame.Continue = false;
就是这样!对Dispatcher.PushFrame
的调用现在将返回并恢复执行
Kent Boggart在这里有一个很好的例子:http://kentb.blogspot.ca/2008/04/dispatcher-frames.html
不幸的是,Kent的博客已不再可用,但可能会找到来自Google缓存的页面快照here。