Каков наиболее эффективный способ управления жизненным циклом объекта с помощью COM-взаимодействия?

StackOverflow https://stackoverflow.com/questions/95834

Вопрос

У меня есть приложение для документооборота Windows, которое использует классы, которые я написал для автоматизации COM.Я открываю Word и Excel из своих классов, используя COM.

В настоящее время я внедряю IDisposable в своем COM-помощнике и использую Marshal.ReleaseComObject().Однако, если мой рабочий процесс завершается с ошибкой, метод Dispose () не вызывается, дескрипторы Word или Excel остаются открытыми, а мое приложение зависает.

Решение этой проблемы довольно простое, но вместо того, чтобы просто решать ее, я хотел бы кое-чему научиться и получить представление о правильном способе работы с COM.Я ищу "лучший" или наиболее эффективный и безопасный способ управления жизненным циклом классов, которым принадлежат дескрипторы COM.Были бы полезны шаблоны, рекомендации или примеры кода.

Это было полезно?

Решение

Я не вижу, какой у вас сбой, который не вызывает метод Dispose().Я выполнил тест с последовательным рабочим процессом, который содержит только действие кода, которое просто генерирует исключение, и метод Dispose() моего рабочего процесса вызывается дважды (это из-за стандартного обработчика событий WorkflowTerminated).Проверьте следующий код:

Program.cs - Программа.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();
        }
    }

Рабочий процесс1.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.");
            }
        }
    }

Я что-то упускаю?Что касается методов, связанных с жизненным циклом объекта Activity (и, следовательно, Workflow), пожалуйста, ознакомьтесь с этим сообщением: Методы "Жизненного цикла" деятельности.Если вам просто нужна общая статья об утилизации, проверьте это.

Другие советы

В принципе, вам не следует полагаться на ручной код для вызова Dispose() для вашего объекта в конце работы.Вероятно, у вас сейчас есть что-то подобное:

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

Вместо этого вам нужно использовать блоки try для перехвата любого исключения, которое может быть вызвано, и вызвать dispose в этот момент.Это канонический способ:

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

Это итак распространено, что C # имеет специальную конструкцию, которая генерирует тот же самый точный код [см. примечание] как показано выше;это то, что вы должны делать большую часть времени (если только у вас нет какой-то специальной семантики построения объекта, которая упрощает работу с ручным шаблоном, подобным приведенному выше):

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

Редактировать:
ПРИМЕЧАНИЕ:Фактически сгенерированный код немного сложнее, чем во втором примере выше, поскольку он также вводит новую локальную область видимости, которая делает вспомогательный объект недоступным после завершения using блок.Это как если бы второй блок кода был окружен символами { }.Это было опущено для уточнения объяснения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top