2010-03-29 53 views
4

這是this question的擴展/下一步我幾分鐘前問。異常調用線程的遠程SOAP調用

我有一個主窗體和一個線程的Delphi應用程序。每隔X秒,線程就會爲遠程對象發出Web服務請求。然後它回到主窗體處理用新信息更新UI。

我以前在我的線程中使用TTimer對象,並且TTimer回調函數運行時,它運行在主線程的上下文中(但遠程Web服務請求確實工作)。這相當於擊敗了單獨線程的目的,所以我現在在我的線程的Execute函數中有一個簡單的循環和睡眠例程。問題是,從GetIMySOAPService()返回時引發異常。

procedure TPollingThread.Execute; 
var 
SystemStatus : TCWRSystemStatus; 
begin 
while not Terminated do 
begin 
    sleep(5000); 
    try 
    SystemStatus := GetIMySOAPService().GetSystemStatus; 
    PostMessage(ParentHandle, Integer(apiSystemStatus), Integer(SystemStatus), 0); 
    SystemStatus.DataContext := nil; 
    LParam(SystemStatus) := 0; 
    except 
    end; 
end; 
end; 

任何人都可以建議爲什麼從線程調用此函數時引發此異常?我確信我忽略了一些基本和簡單的東西。

感謝,鄧肯

+1

你也應該發佈異常類和消息。 – mghie 2010-03-29 16:59:52

+1

異常類是EOleException,並且消息是「CoInitialize尚未被調用」......這已經解決了我的問題,因爲我認爲這需要XML引擎。 – Duncan 2010-03-29 17:39:03

+1

我假設那麼多。做任何與OLE相關的事情都需要調用「CoInitialize()」。主VCL線程在OLE單元的初始化過程中自己完成,對於程序員必須執行的所有其他線程。 – mghie 2010-03-29 17:46:42

回答

5

在你Execute()方法,你必須調用CoInitializeCoUnitialize設置並拆除COM庫。

您的主線程在Application.Initialize()過程中自動執行此操作,但其他線程在調用COM函數之前需要調用CoInitialize

確保您在Execute()方法中調用CoInitialize,而不是在構造函數中調用CoInitialize,因爲構造函數是在父線程(通常是主線程)中執行的。這不是你需要的地方。它必須從您計劃進行COM調用的線程調用。

我建議使用此格式:

try 
    // OleCheck will raise an error if the call fails 
    OleCheck(CoInitializeEx(NIL, COINIT_MULTITHREADED or COINIT_SPEED_OVER_MEMORY)); 
    try 
    // Do work here 
    finally 
    CoUninitialize; 
    end; 
except 
    // We failed, do something 
end; 

這可以讓你捕獲錯誤如果初始化失敗,並確保您撥打CoUninitialize

+1

僅當CoInitializeEx()成功時調用'CoUninitialize()',並且在線程中擁有頂級異常處理程序。 – mghie 2010-03-29 20:13:18

+0

mghie,我知道我的應用程序中有一個不匹配的Co/CoUn,因爲我在那裏拋出了CoInitialize,因爲這就是錯誤說要做的事情....我會在第一次機會修復,但通常會是一個變更請求或升級的錯誤。同時,我會看到什麼樣的問題?內存泄漏,還是會以某種方式崩潰,還是隻是良性? – 2010-03-29 21:06:32

+1

@Chris:我不知道,我希望它是良性的,也許一些窗口和句柄沒有正確發佈。儘管如此,我還是贊成推廣最佳實踐的答案,並且文檔(http://msdn.microsoft.com/en-us/library/ms678543%28VS.85%29.aspx)明確指出,調用需要平衡優雅地關閉COM庫。 – mghie 2010-03-30 07:03:42

2

對於我的未來,自我......我需要的CoInitialize和CoUnInitialize在我的Execute方法:

procedure TPollingThread.Execute; 
begin 

    CoInitialize(nil); 

    while not Terminated do 
    begin 
    // ... 
    end; 


    CoUnInitialize; 
end; 
+4

我也可以建議閱讀錯誤消息。它們可能包含隱藏的提示:) – 2010-03-29 17:57:48