在NativeWindow实例上调用ReleaseHandle之后,为什么它在被处置后(或根本没有收到)仍收到消息?

时间:2018-08-26 15:23:13

标签: c# nativewindow

我正在尝试使用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();
}

任何人都有一个想法,为什么我遇到第一种情况的错误?我只是看不到。

0 个答案:

没有答案