2010-10-12 47 views
2

我正在处理Word自动化,并摆脱“调用被拒绝的被调用者”/“消息过滤器表明应用程序正忙”错误我实现了一个IMessageFilter。该MessageFilter的工作就像一个魅力时,我喜欢直接自动化Word:为什么我的IMessageFilter不总是工作?

Word.Documents.Open(...) 
Document.SaveAs(...) 

但是,当我打电话TOleContainer.DoVerb(ovPrimary),我仍然得到错误当Word正在显示一个模式对话框。为什么MessageFilter不适用于TOleContainers DoVerb方法?

回答

6

“呼叫被被叫方拒绝”是Word处于交互状态时总是得到的,即显示对话框。这不限于Word。它也发生在Excel中,例如当用户编辑单元格时。在用户界面中也不一定非常明显。当你开始编辑一个单元格时,将焦点移动到另一个应用程序并回到Excel中,UI不会给你提示,但它仍然处于“交互”模式,并会拒绝自动化调用,“调用被调用者拒绝”错误。

因此,基本上当您结合用户交互(而不仅仅是在后台进程中使用Word)自动化Word时,您应该准备好获取并处理这些错误。

编辑 如果你想知道Excel或Word是否在交互模式调用任何其他COM方法之前:刚才问的COM服务器是否是“就绪”:

Result := _GetActiveOleObject('Excel.Application'); 

try 
    aSharedInstance := not VarIsClear(Result); 
    if aSharedInstance then 
    Version := Result.Version; // If this produces an exception, then use a dedicated instance. 

    // In case checking the version does not produce an exception, but Excel still isn't 
    // ready, we'll check that as well. 
    // By the way, for some unclear reason, partial evaluation does not work on .Ready, 
    // so we'll do it like this: 
    if aSharedInstance and (StrToIntDef(StringBefore('.', Version), 0) >= EXCEL_VERSION_2002) then 
    aSharedInstance := Result.Ready; 
except 
    aSharedInstance := False; 
end; 

if not aSharedInstance then 
    Result := CreateOleObject('Excel.Application'); 

更新 显然Word没有“Ready”属性(谁说微软是一致的?)。在这种情况下,您需要通过在实际调用之前调用简单(和快速)的属性来自己决定是否准备就绪,并假设当抛出异常时,Word还没有准备好。在上面的例子中,版本在Ready属性之前被检索。如果抛出异常,我们只是假设应用程序(在这种情况下为Excel)尚未准备就绪,并据此进行操作。

线沿线的东西:

while Tries <= MaxTries do 
    try 
    Version := Word.Version; 
    Tries := MaxTries + 1; // Indicate success 
    Word.TheCallYouReallyWantToDo; 
    except 
    Inc(Tries); 
    sleep(0); 
    end; 

注意 Word.Version不抛出一个异常,当一个对话框打开,这样是没有用搞清楚Word是否已准备就绪。 :(你将不得不尝试找到一个可以做到的事情

+0

当然,我知道那就是为什么我实施了这个IMessageFilter。这样,当Word处于模态状态(如显示字体对话框)时,我可以显示“服务器正忙”对话框。问题是,当在TOleContainer上调用DoVerb时,我的IMessageFilter实现不起作用。 – 2010-10-12 11:06:24

+0

@The_Fox:你是说在TOleContainer上调用DoVerb,即使Word不显示对话或以其他方式“参与”?如果是这样的话,那么你的问题对我来说就不清楚了。 – 2010-10-12 11:15:33

+0

不,我的意思是:当我在Word显示模型对话框时调用DoVerb时,出现提到的错误,注册了IMessageFilter。 – 2010-10-12 11:36:06

1

IMessageFilter不处理所有的异常,例如,在某些时候,办公应用程序'暂停'它们的对象模型,此时它不能被调用并抛出:0x800AC472 (VBA_E_IGNORE)

为了解决这个问题,你必须把你的电话在一个循环中,等待它的成功:

while(true) 
{ 
    try 
    { 
     office_app.DoSomething(); 
     break; 
    } 
    catch(COMException ce) 
    { 
     LOG(ce.Message); 
    } 
} 

// continue after successful call 

详情请参阅here