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

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

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

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

Ответы [ 2 ]

1 голос
/ 19 сентября 2008

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

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

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

0 голосов
/ 19 сентября 2008

По сути, вы не должны полагаться на ручной код для вызова 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();
}

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

...