“呼叫被被叫方拒绝”是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是否已准备就绪。 :(你将不得不尝试找到一个可以做到的事情
当然,我知道那就是为什么我实施了这个IMessageFilter。这样,当Word处于模态状态(如显示字体对话框)时,我可以显示“服务器正忙”对话框。问题是,当在TOleContainer上调用DoVerb时,我的IMessageFilter实现不起作用。 – 2010-10-12 11:06:24
@The_Fox:你是说在TOleContainer上调用DoVerb,即使Word不显示对话或以其他方式“参与”?如果是这样的话,那么你的问题对我来说就不清楚了。 – 2010-10-12 11:15:33
不,我的意思是:当我在Word显示模型对话框时调用DoVerb时,出现提到的错误,注册了IMessageFilter。 – 2010-10-12 11:36:06