Проблема с получением интерфейса из dll
Опубликовано 09.12.2010 г. 17:27
решил реализовать вроде как простую вещь: есть некоторый интерфейс, класс его поддерживающий, реализован в библиотеке. Есть функция экспорта, создает объект класса, возвращает ссылку на интерфейс. Главное приложение используя функцию библиотеки получает ссылку на интерфейс. Поскольку опыта в написании таких вещей нет, то ничего видимо и не работает (: как сделать?
Алгоритм следующий:
- Создаем новый проект- VCL Forms приложение testProject.exe.
- Добавляем в группу проектов новую DLL библиотеку – testLib.dll.
- В проект библиотеки добавляем новый модуль – testIntf.pas, в интерфейсной части которого описываем требуемый пустой интерфейс ITestInterface.
type ITestInterface = interface end;
- В главный файл библиотеки добавляем описание класса TTestObject, предка TInterfacedObject, поддерживающего интерфейс ITestInterface
library testLib; uses testIntf in 'testIntf.pas'; {$R *.res} type TTestObject = class(TInterfacedObject, ITestInterface) end;
- Здесь же добавляем функцию для создания объекта, с возвратом указателя на интерфейс. Модель вызова safecall.
function ExportObject():ITestInterface; safecall; begin result := TTestObject.Create(); end;
- Добавляем имя функции в список экспортируемых.
exports ExportObject;
- Сохраняем всю группу проектов.
- К проекту testProject подключаем файл описания интерфейса testIntd.pas
- Определяем сигнатуру экспортируемой функции
var getObject : function(): ITestInterface; safecall;
- описываем необходимые переменные
x : ITestInterface; hLib : THandle;
- Загружаем библиотеку.
hLib := LoadLibrary('testLib.dll');
- Получаем точку входа в функцию экспорта объекта.
@getObject := GetProcAddress(hLib,'ExportObject');
- Вызываем функцию, получаем ссылку на интерфейс
x := getObject();
- тут инициализируется объект Application, работает приложение, и закрывается.
Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TForm1, Form1); Application.Run;
- Обнуляем ссылку на интерфейс
x := nil;
- Выгружаем библиотеку.
FreeLibrary(hLib);
var getObject : function(var x : ITestInterface):HResult; stdcall; ... getObject(x);то все работает. внимание вопрос: почему в появляется дополнительная ссылка на интерфейс? мозг на грани катастрофы. подскажите кто-нибудь? :)
09.12.2010 в 22:13
Оно при выходе из функции 1,
при присваивании переменной +1. 1+1=2
Переменную убил -1
var
src: ISourceDataset;
Типовой пример, как надо:
function GetSourceDataset(out Dataset: ISourceDataset): Boolean;
...
if not GetSourceDataset(src) then
Assert(False, 'ошибка');
Ну или не зависимо от pascal:
function GetSourceDataset(out Dataset: ISourceDataset): hResult;
...
if not Succeeded(GetSourceDataset(src)) then
Assert(False, 'ошибка');
или
...
OleCheck(GetSourceDataset(src));
09.12.2010 в 23:29
соответствует
или вы хотите сказать что через safecall нельзя интерфейсы возвращать чтоли? да и вобще как результат любой функции.
12.12.2010 в 23:40
http://www.gunsmoker.ru/2008/12/1.html
Надеюсь, поможет.
13.12.2010 в 11:11
Да, иначе из функции вообще ничего не вернуть, тк если по выходу будет RefCount=0 => Free.
13.12.2010 в 11:31
мне что то казалось, что результат функции живет не до конца end'а вызывающей подпрограммы, а как то уничтожается сразу по возврату результата. Иными словами мы имеем неявную ссылку на интерфейс, если смотреть со стороны вызывающей программы.
05.01.2011 в 21:00
Вот так сработает:
var
i: IInterface;
h: Cardinal;
a: function: IInterface; safecall;
procedure a1();
begin
h := LoadLibrary('project2.dll');
a := windows.GetProcAddress(h, 'a');
i := a();
end;
procedure a2();
begin
end;
a1; //пункт 14 в твоём сообщении
//пункт 15
i := nil; //пункт 16
FreeLibrary(h);
т.е. вынесением пункта 14 в отдельную процедуру. Иначе текущий контекст рассматривается как одна сплошная процедура и освобождение памяти (сброс счётчика у интерфейса) не происходит до выхода из неё.
09.01.2011 в 19:03