Pergunta

Eu tenho um aplicativo Windows Workflow que as classes usos que eu escrevi para automação COM. Estou abrindo Word e Excel a partir de minhas aulas usando COM.

Atualmente estou implementando IDisposable na minha COM ajudante e usando Marshal.ReleaseComObject (). No entanto, se o meu fluxo de trabalho falhar, o método Dispose () não está sendo chamado e as alças do Word ou Excel permanecer aberto e meus aplicativo trava.

A solução para este problema é bastante simples, mas ao invés de apenas resolvê-lo, eu gostaria de aprender alguma coisa e insight ganho para o caminho certo para o trabalho com COM. Eu estou procurando o "melhor" ou mais eficiente e mais segura maneira de lidar com o ciclo de vida das classes que possuem as alças COM. Padrões, melhores práticas, ou código de amostra seria útil.

Foi útil?

Solução

Não consigo ver o que falha você tem que não chama o método Dispose (). Fiz um teste com um fluxo de trabalho seqüencial que contém apenas uma atividade de código que apenas lança um método Dispose () do meu fluxo de trabalho é chamado duas vezes (isto é por causa do manipulador de eventos padrão WorkflowTerminated) exceção e. Verifique o seguinte código:

Program.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();
        }
    }

Workflow1.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.");
            }
        }
    }

Estou faltando alguma coisa? Quanto aos métodos relacionados ciclo de vida-de actividade (e, consequentemente, de um fluxo de trabalho) objeto, verifique este post: Atividade "Lifetime" Métodos . Se você quer apenas um artigo genérico sobre a eliminação, verificar este .

Outras dicas

Basicamente, você não deve confiar em código mão para chamar Dispose () em seu objeto no final do trabalho. Você provavelmente tem algo parecido com isso agora:

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

Em vez disso, você precisa usar blocos try para capturar qualquer exceção que pode ser desencadeada e dispor chamada naquele ponto. Esta é a forma canônica:

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

Este é de modo comum que C # tem uma construção especial que gera o mesmo código exacta [ver nota] como mostrado acima; isto é o que você deveria estar fazendo a maior parte do tempo (a menos que você tem alguns semântica especial de construção objeto que fazem um padrão manual de como o acima mais fácil trabalhar com):

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

Editar :
NOTA: O código real gerado é um pouco mais complicado do que o segundo exemplo acima, porque ele também introduz um novo escopo local que faz com que o objeto auxiliar indisponíveis após o bloco using. É como se o segundo bloco de código foi cercado por {} 's. Que foi omitido para esclarecer da explicação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top