2011-07-19 85 views
8

我正試圖找到一種安全/確定性的方式來釋放封裝在OleVariant中的接口。在OleVariant後面釋放接口的正確方法是什麼?

AFAICS Delphi在程序結束時發佈了接口引用,但在我的情況下,我必須先做,因爲我必須關閉COM。

procedure Test; 
var 
    LLibrary: OleVariant; 
begin 
    CoInitialize(nil); 
    try 
    LLibrary := Null; 
    try 
     LLibrary := CreateOleObject(LibraryName); 
    finally 
     LLibrary := Unassigned; // <-- I would like to release the interface here 
    end; 
    finally 
    CoUninitialize; // <-- Shutdown of COM 
    end; 
end; // <-- The compiler releases the interface here 

我雖然把OleVariant在一個額外的類的實例,我可以釋放我叫CoUninitialize前。

procedure Test; 
var 
    Container: TLibraryContainer; // Holds the OleVariant 
begin 
    CoInitialize(nil); 
    try 
    Container := TLibraryContainer.Create; 
    try 
     {...} 
    finally 
     Container.Free; 
    end; 
    finally 
    CoUninitialize; 
    end; 
end; 

這個解決方案是安全的還是有更好的解決方案我忽略了?

回答

9

編譯器明確使用隱式本地接口變量作爲來自CreateOleObject的返回值。然後在例程結束時釋放,對於你來說太遲了。

有幾種方法可以打敗這個。首先,您可以明確CreateOleObject返回的IDispatch接口參考。這使您可以控制其使用期限。

procedure Test; 
var 
    intf: IDispatch; 
    LLibrary: OleVariant; 
begin 
    CoInitialize(nil); 
    try 
    intf := CreateOleObject(LibraryName); 
    try 
     LLibrary := intf; 
    finally 
     VarClear(LLibrary); 
     intf := nil; 
    end; 
    finally 
    CoUninitialize; 
    end; 
end; 

另一種方法是移動調用CreateOleObject與它自己的範圍內獨立的程序代碼。

procedure DoWork; 
var 
    LLibrary: OleVariant; 
begin 
    LLibrary := CreateOleObject(LibraryName); 
    //do stuff with LLibrary 
end; 

procedure Test; 
begin 
    CoInitialize(nil); 
    try 
    DoWork; 
    finally 
    CoUninitialize; 
    end; 
end; 

由於隱含本地參考的DoWork範圍內被釋放在DoWork結束,因此在運行CoUninitialize之前。

我的建議是使用更清潔的第二個選項,並強制編譯器代表您完成工作。

+2

唯一真正的選擇是使用輔助例程,除非您喜歡計數函數調用並檢查生成的彙編代碼以確保沒有隱藏的局部變量。 +1用於調用你的'DoWork'例程...'DoWork',查看我刪除的答案以獲取詳細信息。 –

+0

@Cosmin我同意第二個選擇更好。 –

+0

其實我真正的代碼有點複雜,我認爲我將不得不使用你的第一個變體,但我會嘗試重構代碼,以便我可以使用第二個變體。 :) –

相關問題