Pregunta

Tengo una aplicación de flujo de trabajo de Windows que utiliza clases que escribí para la automatización COM.Estoy abriendo Word y Excel desde mis clases usando COM.

Actualmente estoy implementando IDisposable en mi asistente COM y usando Marshal.ReleaseComObject().Sin embargo, si mi flujo de trabajo falla, no se llama al método Dispose() y los controladores de Word o Excel permanecen abiertos y mi aplicación se bloquea.

La solución a este problema es bastante sencilla, pero en lugar de simplemente resolverlo, me gustaría aprender algo y comprender la forma correcta de trabajar con COM.Estoy buscando la "mejor" o más eficiente y segura forma de manejar el ciclo de vida de las clases propietarias de los identificadores COM.Serían útiles los patrones, las mejores prácticas o el código de muestra.

¿Fue útil?

Solución

No puedo ver qué falla tienes que no llama al método Dispose().Hice una prueba con un flujo de trabajo secuencial que contiene solo una actividad de código que simplemente genera una excepción y el método Dispose() de mi flujo de trabajo se llama dos veces (esto se debe al controlador de eventos WorkflowTerminate estándar).Verifique el siguiente código:

Programa.cs

    class Program
    {
        static void Main(string[] args)
        {
            using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
            {
                AutoResetEvent waitHandle = new AutoResetEvent(false);
                workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) 
                {
                    waitHandle.Set();
                };
                workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
                {
                    Console.WriteLine(e.Exception.Message);
                    waitHandle.Set();
                };

                WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow1));
                instance.Start();

                waitHandle.WaitOne();
            }
            Console.ReadKey();
        }
    }

Flujo de trabajo1.cs

    public sealed partial class Workflow1: SequentialWorkflowActivity
    {
        public Workflow1()
        {
            InitializeComponent();
            this.codeActivity1.ExecuteCode += new System.EventHandler(this.codeActivity1_ExecuteCode);
        }

        [DebuggerStepThrough()]
        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
            Console.WriteLine("Throw ApplicationException.");
            throw new ApplicationException();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Here you must free your resources 
                // by calling your COM helper Dispose() method
                Console.WriteLine("Object disposed.");
            }
        }
    }

¿Me estoy perdiendo de algo?Con respecto a los métodos relacionados con el ciclo de vida de un objeto Actividad (y, en consecuencia, de un flujo de trabajo), consulte esta publicación: Métodos de actividad "de por vida".Si solo desea un artículo genérico sobre cómo deshacerse, consulte este.

Otros consejos

Básicamente, no debes confiar en el código manual para llamar a Dispose() en tu objeto al final del trabajo.Probablemente tengas algo como esto ahora mismo:

MyComHelper helper = new MyComHelper();
helper.DoStuffWithExcel();
helper.Dispose();
...

En su lugar, debe utilizar bloques try para detectar cualquier excepción que pueda desencadenarse y llamar a disponer en ese punto.Esta es la forma canónica:

MyComHelper helper = new MyComHelper();
try
{
    helper.DoStuffWithExcel();
}
finally()
{
    helper.Dispose();
}

Esto es entonces Es común que C# tenga una construcción especial que genera el mismo código exacto [ver nota] como se muestra arriba;esto es lo que deberías hacer la mayor parte del tiempo (a menos que tengas alguna semántica de construcción de objetos especial que haga que sea más fácil trabajar con un patrón manual como el anterior):

using(MyComHelper helper = new MyComHelper())
{
    helper.DoStuffWithExcel();
}

EDITAR:
NOTA:El código real generado es un poco más complicado que el segundo ejemplo anterior, porque también introduce un nuevo alcance local que hace que el objeto auxiliar no esté disponible después de la using bloquear.Es como si el segundo bloque de código estuviera rodeado por { }.Eso se omitió para aclarar la explicación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top