COM Interop - 等待Excel完成操作

时间:2010-04-06 15:24:12

标签: .net com automation com-interop

我正在使用Excel和其他Office自动化软件进行一些COM Interop工作。

Co-Worker向我提到我需要等待这些自动化服务器在向他们发出命令后准备好。

但是,我看不到这个的目的,因为在自动化服务器完成给定任务之前,所有调用都不会阻塞吗?

例如我通常会写:

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

我的同事说我需要在调用之后休眠,因为Automation Server仍然可以处理创建和初始化对象。

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 个答案:

答案 0 :(得分:1)

访问繁忙的out-proc自动化服务器时,您确实会遇到异常。在Office的情况下,这种情况的一种方式是,如果您有一个在打开文档时运行的宏。如果连接到打开了对话框的Office应用程序实例,也会出现问题。

This article描述了如何通过实现IOleMessageFilter错误处理程序来避免这种情况。本文是关于Visual Studio的自动化,但其原理和技术与自动化其他out-proc自动化服务器(如Office)的原理和技术相同。

答案 1 :(得分:1)

下面是一个处理此问题的简单方法。我最近必须与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,因为我不想要它,但如果你需要它,只需在MakeRiskyCOMCall方法中设置一个COMException变量,该方法在调用方法中作用域。您还可以检查指示等待忙碌过程的特定HResult,并更快地为其他HResults失败。这个解决方案很快,并且避免了所有COM互操作性混乱,它的缺点是它不漂亮,但它可以工作,并且更容易找到代码的维护者(我认为)。