我正在尝试使用NativeWindow
类来从WPF窗口上打开的模式CommonDialog
中抓取句柄。为此,我要钩上父窗口,以WM_ACTIVATE
的{{1}}监听WParam
消息。这意味着主窗口失去焦点,因此WA_INACTIVE
包含获得焦点的窗口LParam
,即CommonDialog。该部分按预期工作。
调用几次后不起作用,我不断收到关于在垃圾收集的委托上进行回调的错误(请参阅下文。)我不知道为什么。
这是课程...
HWnd
这是我如何使用它的一个简单示例...
public class DialogHwndScope : NativeWindow, IDisposable {
public DialogHwndScope(Window parentWindow = null){
if(parentWindow == null)
parentWindow = Application.Current.MainWindow
?? throw new ArgumentNullException(nameof(parentWindow), $"{nameof(parentWindow)} can't be null if there is no main window.");
var windowInteropHelper = new System.Windows.Interop.WindowInteropHelper(parentWindow);
windowInteropHelper.EnsureHandle();
AssignHandle(windowInteropHelper.Handle);
}
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
// If we're losing focus, grab the handle of the window gaining focus
if((WM)m.Msg != WM_ACTIVATE || (WA)m.WParam != WA_INACTIVE)
return;
// Stop listening to the main window because we're done
ReleaseHandle();
// At this point, although we're still in the using scope,
// we shouldn't be getting any more messages
var childHandle = m.LParam;
// Insert code to do something with 'childHandle' here
}
public void Dispose(){
// This is redundant if we've already released it above (which we should have by now),
// or it could have been released automatically if the window received a WM_DESTROY message,
// but per MSDN, it's safe to call again so we can blindly call it again here without worry.
ReleaseHandle();
}
}
这是我不断收到的消息...
托管调试助手“ CallbackOnCollectedDelegate” Message =托管调试助手'CallbackOnCollectedDelegate':'对类型为'System.Windows.Forms!System.Windows.Forms.NativeMethods + WndProc :: Invoke'的垃圾收集的委托进行了回调。这可能会导致应用程序崩溃,损坏和数据丢失。当将委托传递给非托管代码时,托管应用程序必须使它们保持活动状态,直到确保永远不会调用它们为止。'
我的怀疑是因为我试图在WndProc中解开窗口,但是我看不到为什么会成为问题,因为它会更改窗口proc回调的地址,这只会影响下一条要通过的消息,而不影响我们正在处理的当前消息。但是,确实确实是这样,因为如果我将其更改为以下内容,它将起作用。
var testDialog = new OpenFileDialog();
using (new DialogHwndScope()) {
testDialog.ShowDialog();
}
任何人都有一个想法,为什么我遇到第一种情况的错误?我只是看不到。