代码之家  ›  专栏  ›  技术社区  ›  user113476

COM互操作-等待Excel完成操作

  •  2
  • user113476  · 技术社区  · 14 年前

    我正在用Excel和其他办公自动化软件做一些COM互操作工作。

    一位同事向我提到,我需要等待这些自动化服务器在向它们发出命令后准备就绪。

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

    例如,我通常会写:

    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完成(如果它实际上不阻止)?

    2 回复  |  直到 14 年前
        1
  •  1
  •   Audie    14 年前

    下面是一个简单的处理方法。我最近不得不与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,它指示正在等待繁忙的进程,而对于其他hresult,则会更快地失败。这个解决方案很快并且避免了所有的COM互操作混乱,缺点是它不漂亮,但是它可以工作,而且对于代码维护者来说更容易理解(我认为)。

        2
  •  1
  •   to StackOverflow    14 年前

    当访问一个正忙的Out-Proc自动化服务器时,您确实可以得到一个异常。对于Office,一种可能发生这种情况的方法是,如果打开文档时有一个宏在运行。如果连接到打开了对话框的Office应用程序实例,也会出现问题。

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