2011-07-19 3 views
8

私は、OleVariantにカプセル化されたインターフェイスを解放するための安全で決定論的な方法を見つけようとしています。OleVariantの背後にあるインタフェースを解放する正しい方法は何ですか?

AFAICS Delphiはプロシージャの終了時にインターフェイス参照を解放しますが、私の場合、COMをシャットダウンする必要があるため、前もって実行する必要があります。私はCoUninitializeを呼び出す前に、私は解放することができ、余分なクラスのインスタンスでOleVariantを置くものの

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 

私は。

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; 

暗黙のローカル参照は、あなたがCoUninitializeを実行する前に、それはそれゆえDoWorkの終了時に解放されDoWorkの範囲内であるので。

私のお勧めは、よりクリーンな2番目のオプションを使用し、コンパイラがあなたの代わりに作業を実行することです。

+2

実際のオプションは、関数呼び出しをカウントし、生成されたアセンブラコードを検査して隠れたローカル変数がないことを確認しない限り、セカンダリルーチンを使用する唯一のオプションです。あなたの 'DoWork'ルーチンを呼び出すための+1 ...' DoWork'、詳細については私の削除された答えを見てください。 –

+0

@コスミン私は第2の選択肢が優れていることに同意します。 –

+0

実際には、私の実際のコードはもう少し洗練されています。私はあなたの最初の変種を使わなければならないと思いますが、私は2番目のコードを使用できるようにコードをリファクタリングしようとします。 :) –

関連する問題