8

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;

この解決策は安全ですか、それとも私が見落としていたより良い解決策がありますか?

4

1 に答える 1

9

コンパイラは明らかに、からの戻り値に暗黙のローカルインターフェイス変数を使用していますCreateOleObject。これは、ルーチンの最後にリリースされますが、遅すぎます。

これを打ち負かすにはいくつかの方法があります。まず、IDispatchによって返されるインターフェイス参照について明示的にすることができますCreateOleObject。これにより、その寿命を制御できます。

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番目のオプションを使用することです。

于 2011-07-19T10:41:51.293 に答える