2010-10-12 52 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