WPF - 是否必须处理 HwndSource?

Boh*_*hoo 5 wpf interop idisposable

我在HwndSource不是主窗口的 WPF 窗口中使用,以便挂钩窗口过程 (WndProc) 以接收一些消息:

WinSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
WinSource.AddHook(new HwndSourceHook(WndProc));
Run Code Online (Sandbox Code Playgroud)

HwndSource实施IDisposable. MSDN 不清楚我何时/应该处理它。HwndSource.FromHwnd的文档解释了上述技术:

您可以使用此方法为不是显式互操作窗口的窗口返回 HwndSource。这样做的程序是:

  1. 创建一个 WindowInteropHelper 实例(提供主 Window 作为构造函数参数)。
  2. 从该 WindowInteropHelper 实例获取 Handle 属性的值。
  3. 将该 HWND 值作为参数传递给 FromHwnd。

进而:

如果您随后想要向窗口添加常规 AddHook 消息处理,则此技术非常有用。但是,每当您创建 HwndSource 时,您也有责任销毁它。即使已释放应用程序 HwndSource 的 Application 对象,也是如此。

(重点是我的)

但是,在HwndSource类文档中,我们看到:

对象生存期

HwndSource 是常规公共语言运行时 (CLR) 对象,其生命周期由垃圾收集器管理。因为 HwndSource 表示非托管资源,所以 HwndSource 实现 IDisposable。[...] 对于某些互操作场景,可能需要从互操作代码中显式调用 Dispose。

关于钩子:

实际的钩子由弱引用保存。因此,请确保您管理钩子委托的生命周期。

Dav*_*Caz 0

我无法对此给出完整的答案,但根据最近的经验,我可以说您不应该HwndSource太早处置该对象 - 具体来说,在它引用的窗口关闭之前根本不应该处置。

我只是在调试一个这样完成的场景:

using(var source = HwndSource.FromHwnd(window.HWnd()))
{
     source.AddHook(hook);
}
Run Code Online (Sandbox Code Playgroud)

其结果是,在源被处理后,窗口立即变得不起作用(不再处理消息)。

简要查看 的参考源FromHwnd(),似乎它总是会为同一窗口返回相同的对象。我认为这就是为什么你不能source仅仅因为你自己的代码已经完成了它就进行处置。显然HwndSource.Dispose()不仅清理HWndSource对象,还清理一些非托管窗口本身。

注意到这一点后,现在我还看到 HWndSource文档说:

同步调用Dispose立即销毁Win32窗口

这似乎是我所观察到的。