Как правильно освободить интерфейс за 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;

Это решение безопасно или есть лучшее решение, которое я пропустил?

1 ответ

Решение

Компилятор явно использует неявную переменную локального интерфейса для возвращаемого значения из 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,

Я рекомендую использовать второй вариант, который чище и заставляет компилятор выполнять работу от вашего имени.

Другие вопросы по тегам