我正在使用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完成之前是否有“等待”的方法(如果它实际上没有阻塞)?
答案 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互操作性混乱,它的缺点是它不漂亮,但它可以工作,并且更容易找到代码的维护者(我认为)。