2011-07-19 2 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. Затем это освобождается в конце процедуры, слишком поздно для вас.

Существует несколько способов победить это. Прежде всего, вы можете явно указать ссылку на интерфейс 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

Единственная реальная опция - использовать вторичную подпрограмму, если вам не нравятся вызовы функций подсчета и проверка сгенерированного кода ассемблера, чтобы убедиться, что нет скрытых локальных переменных. +1 для вызова вашей подпрограммы 'DoWork' ...' DoWork', см. Мой удаленный ответ для деталей. –

+0

@Cosmin Я согласен, что второй вариант лучше. –

+0

На самом деле мой настоящий код немного сложнее, и я думаю, что мне придется использовать свой первый вариант, но я попытаюсь реорганизовать код, чтобы я мог использовать второй. :) –

Смежные вопросы