Реализация метода QueryInterface в классах, наследующих TInterfacedObject в Delphi
Вопрос, заданный пользователем, связан с реализацией метода QueryInterface в классе, который наследует TInterfacedObject в среде разработки Delphi. Метод QueryInterface является частью интерфейса IUnknown, который является базовым для всех COM-объектов. В Delphi IUnknown объявляется следующим образом:
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
Параметр Obj является параметром вывода без указанного типа. В классе, наследующем TInterfacedObject, необходимо обработать метод QueryInterface, чтобы возвращать объекты, поддерживающие запрошенный интерфейс. Пример реализации:
function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if IsEqualGUID(IID, IFooBar) then
begin
Obj := (TFooBar.Create(Self) as IFooBar);
Result := S_OK;
end
else
Result := inherited QueryInterface(IID, {out}Obj);
end;
Однако, при попытке присвоить значение параметру Obj, компилятор выдает ошибку, указывая, что оператор не может быть применен к данному типу операнда.
Решение проблемы заключается в том, чтобы привести тип параметра Obj к типу интерфейса, который вы хотите вернуть. Это позволит компилятору правильно интерпретировать присваивание:
IFooBar(Obj) := TFooBar.Create(Self) as IFooBar;
Также стоит отметить, что после создания объекта интерфейса необходимо вызвать метод _AddRef, чтобы увеличить счетчик ссылок на объект. В данном случае, если использовать тип Obj как интерфейс IFooBar перед присваиванием, то компилятор автоматически вызовет _AddRef при необходимости.
Стоит помнить, что в COM-объектах важно соблюдать правила управления ресурсами, в том числе правильное управление счетчиками ссылок.
Альтернативный подход
Если задача состоит в том, чтобы возвращать один и тот же объект IUnknown при запросе, можно использовать ключевое слово implements и делегировать новый интерфейс адаптер-классу, созданному в геттере свойства. Однако, это может привести к необходимости кэширования объектов для каждого поддерживаемого интерфейса.
Пример альтернативной реализации
Можно также попробовать следующий подход:
function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if IsEqualGUID(IID, IFooBar) then
Result := TFooBar.Create(Self).QueryInterface(IID, Obj)
else
Result := inherited QueryInterface(IID, {out}Obj);
end;
В данном случае, вызов QueryInterface на объекте TFooBar автоматически обработает необходимый _AddRef.
Заключение
При реализации метода QueryInterface важно учитывать правила COM, в частности, управление ссылочными счетчиками. Приведенные примеры демонстрируют, как можно правильно обработать вызов метода QueryInterface в классе, наследующем TInterfacedObject, и вернуть интерфейс, поддерживаемый объектом.
Метод `QueryInterface` должен быть правильно реализован в классах, наследующих `TInterfacedObject` в Delphi, для корректной работы с интерфейсами COM и управления ссылочными счетчиками.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.