26

VS2008、.NET 2、VB.NET、XP ...

我有一个 Windows 窗体,带有一个 WebBrowser 控件和一个关闭按钮,它只执行Me.Close. 表单的取消按钮设置为关闭按钮,这样我就可以按 ESC 关闭表单。

DocumentText在加载事件中设置了 WebBrowser 控件的属性,并显示了 HTML。

从 Visual Studio 运行应用程序,如果单击“关闭”按钮,表单将关闭且没有错误。

如果我按下 ESC 按钮,我会得到

检测到 RaceOnRCWCleanup 消息:已尝试释放正在使用的 RCW。RCW 正在活动线程或其他线程上使用。尝试释放正在使用的 RCW 可能会导致损坏或数据丢失。

如果我在 VS 之外运行应用程序,我不会收到任何错误。

任何想法a)为什么会出现错误,以及b)如何防止或抑制它?

提前谢谢了。

4

1 回答 1

40

这不是错误,而是警告。由托管调试助手 (MDA) 生成,它是托管代码调试器的扩展,它认为它在您的代码中发现了问题。鞋子合脚。您正在使用 RCW,WebBrowser 是一个 COM 控件。你正在扼杀 RCW,你正在关闭你的表格。MDA 介入是因为它认为它看到了正在使用的 Web 浏览器,并且在请求完成之前它就被杀死了。这通常只有在您在代码中使用线程时才有意义。

你是?如果没有,请不要为此失眠。COM 使用引用计数,因无法解析循环引用而臭名昭著。


好的,我得到了一个重现,由评论启用。是的,这是由表单的 CancelButton 属性或按钮的 DialogResult 属性触发的。当 WB 获得焦点时会发生这种情况,它会看到 Escape 键按下。ActiveX 管道的一部分是告诉容器有关它的信息,以便它可以响应应该有副作用的击键。快捷键,Tab,Enter。和逃脱。如果按钮然后关闭窗体,调试器会看到 WB 被释放,而堆栈上的 RCW 代码中有活动的堆栈帧。危险在于,当 COM 组件释放后调用代码返回时,这可能会导致崩溃,这种情况并不少见。

看到这种崩溃是不太可能的,但我可以想象,当终结器线程在按钮的 Click 事件返回之前运行时,这可能会发生爆炸。MDA 和潜在崩溃的解决方法是延迟关闭窗体,直到 ActiveX 代码停止运行。使用 Control.BeginInvoke() 优雅地完成。像这样:

    private void CancelButton_Click(object sender, EventArgs e) {
        this.BeginInvoke((MethodInvoker)delegate { this.Close(); });
    }
于 2009-12-10T02:24:53.160 回答