COM Interop - дождитесь завершения работы Excel - PullRequest
2 голосов
/ 06 апреля 2010

Я занимаюсь COM-взаимодействием с Excel и другим программным обеспечением Office Automation.

Сотрудник упомянул мне, что мне нужно подождать, пока эти серверы автоматизации будут готовы после подачи им команды.

Однако я не вижу цели этого, так как не все вызовы блокируются, пока сервер автоматизации не выполнит заданную задачу?

Например, я обычно пишу:

Dim o as AutomationObject = AutomationServer.CreateObject(x, y, z)
o.Property ' could throw COM exception!!????

Мой коллега говорит, что мне нужно поспать после этого вызова, потому что сервер автоматизации еще может работать над созданием и инициализацией объекта.

Dim o as AutomationObject = AutomationServer.CreateObject(x, y, z)
Threading.Sleep(5000) ' wait for AutomationServer to "become ready"
o.Property ' could still throw COM exception!!????

Проблема, с которой я сталкиваюсь, заключается в том, что вызовы AutomationServer должны блокироваться до тех пор, пока AutomationServer не завершит или не завершит то, над чем он работал, или, по крайней мере, это должна быть проверка цикла, если «o» - ничто, но это не имеет смысла. потому что, как только вызов вернется, все готово!

У меня вопрос: есть ли какая-либо польза от сна после вызова AutomationServer? Есть ли способ «подождать», пока AutomationServer не завершит работу (если он фактически не блокируется)?

Ответы [ 2 ]

1 голос
/ 06 апреля 2010

Простой способ справиться с этим ниже.Недавно мне пришлось взаимодействовать с Visual Studio, и я обнаружил, что это хорошо работает, если вы хотите быстро потерпеть неудачу на COM-объекте, который становится бесконечно занятым.Посмотрите, будет ли это работать для вас:

    delegate void COMWrapper();

    private void MakeRiskyCOMCall(COMWrapper doThis)
    {
        bool sendAgain = true;
        int count = 0;

        while (sendAgain)
        {
            try
            {
                doThis();
                sendAgain = false;
            }
            catch (COMException ex)
            {
                System.Threading.Thread.Sleep(50);
                sendAgain = count > 100 ? false : true;
                if (!sendAgain)
                {
                    throw;
                }
            }
            finally { count++; }
        }
    }

После того, как у вас есть этот делегат и метод в области видимости, то вот примеры вызова метода и доступа к свойству с использованием анонимного делегирования.

    // property access
    vsDisplay display;
    MakeRiskyCOMCall(delegate() { display = dte.DisplayMode; });
    if (display == null)
        throw new Exception("VS Display not set");        

    //simple method call
    MakeRiskyCOMCall(delegate() { dte.Solution.Close(true); });

Я намеренно скрыл COMException, так как я не хотел его, но если вам это нужно, просто установите переменную COMException в методе MakeRiskyCOMCall, который находится в области действия вызывающего метода.Вы также можете проверить конкретный результат HResult, указывающий на ожидание занятого процесса и более быстрый сбой для других результатов HR.Это быстрое решение, позволяющее избежать всей неразберихи с COM-взаимодействием, и его недостатком является то, что оно не очень красиво, но работает и его легче выяснить для тех, кто сопровождает ваш код (я думаю).

1 голос
/ 06 апреля 2010

Вы действительно можете получить исключение при доступе к серверу автоматизации Out-Proc, который занят.В случае Office это может произойти, если у вас есть макрос, который запускается при открытии документа.У вас также будут проблемы, если вы подключитесь к экземпляру приложения Office, у которого открыто диалоговое окно.

В этой статье описывается, как этого избежать, реализовав обработчики ошибок IOleMessageFilter.Эта статья посвящена автоматизации Visual Studio, но принципы и методы одинаковы для автоматизации других серверов автоматизации, таких как Office.

...