.net - ¿Por qué se produce un error RaceOnRCWCleanup al cerrar un formulario con el control WebBrowser?
winforms webbrowser-control (1)
VS2008, .NET 2, VB.NET, XP ...
Tengo un formulario de Windows, con un control WebBrowser y un botón Cerrar, que solo hace un Me.Close
. El botón de cancelación del formulario se establece en el botón Cerrar, de modo que puedo presionar ESC para cerrar el formulario.
Establecí la propiedad DocumentText
del control WebBrowser en el evento de carga y se muestra el HTML.
Al ejecutar la aplicación desde Visual Studio, si hago clic en el botón Cerrar, el formulario se cierra sin error.
Si presiono el botón ESC obtengo
Se detectó RaceOnRCWCleanup Mensaje: Se ha intentado liberar un RCW que está en uso. El RCW está en uso en el hilo activo u otro hilo. Intentar liberar un RCW en uso puede causar daños o pérdida de datos.
Si ejecuto la aplicación fuera de VS, no obtengo ningún error.
¿Alguna idea a) por qué el error, y b) cómo prevenirlo o suprimirlo?
Muchas gracias de antemano.
No es un error, es una advertencia. Producido por un Asistente de depuración administrado (MDA), una extensión del depurador para el código administrado, que cree que está viendo algo mal en su código. El zapato encaja. Está utilizando un RCW, WebBrowser es un control COM. Estás matando a la RCW, estás cerrando tu forma. La MDA interviene porque cree que está viendo que el navegador web está en uso y que se mata antes de que se complete la solicitud. Eso normalmente solo tendría sentido si está usando un hilo en su código.
¿Eres tú? Si no, no pierdas el sueño por eso. COM usa el recuento de referencias, notorio por no poder resolver referencias circulares.
Está bien, tengo un repro para esto, habilitado por los comentarios. Sí, esto se activa mediante la propiedad CancelButton del formulario o la propiedad DialogResult del botón. Esto sucede cuando el WB tiene el foco, ve presionar la tecla Escape. Parte de la instalación de ActiveX es informarle al contenedor para que pueda responder a las pulsaciones de tecla que deberían tener un efecto secundario. Atajos de teclado, Tabulador, Entrar. Y escapar. Si el botón luego cierra el formulario, el depurador ve que el WB se elimina mientras hay marcos de pila activos del código RCW en la pila. El peligro es que esto podría causar un bloqueo cuando el código llamado regresa desde que se lanzó el componente COM, no es raro.
Ver este choque es bastante improbable, pero puedo imaginar que esto podría bombardear cuando el hilo finalizador se ejecuta justo antes de que regrese el evento Click del botón. La solución alternativa para la MDA y el bloqueo potencial es retrasar el cierre del formulario hasta que el código ActiveX deje de ejecutarse. Hecho con elegancia con Control.BeginInvoke (). Me gusta esto:
private void CancelButton_Click(object sender, EventArgs e) {
this.BeginInvoke((MethodInvoker)delegate { this.Close(); });
}