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