Я к dll (so) прилагаю модуль для добавления в проект. Этот модуль содержит (простой) хелпер, который не только строки помогает возвращать, но и прозрачной трансляцией исключений занимается, версию реализации интерфейса контролирует и ещё по мелочи. Идея следующая: библиотека экспортирует только одну функцию: GetMyInterfase(Helper), которая получает экземпляр хелпера и возвращает интерфейс.
Всё, что надо экспортировать из библиотеки, оформлено как методы интерфейса. Удобно.
Хелпер, кроме прочего, имеет метод:
- Код: Выделить всё
procedure TIHtCallbackHelper.AllocStr(Src: PChar; Chars: integer; var Dst); stdcall;
var Buf: array[0..1023] of Char;
s: ^string;
begin
try
s:= @Dst;
if Chars < 0 then // autodetect, zero terminated
Chars:= StrLen(Src);
if Chars = 0 then
s^:= '' // empty
else begin
SetLength(s^, Chars);
Move(Src^, Pointer(s^)^, SizeOf(Char) * Chars);
end;
except
ExceptionErrorMessage(ExceptObject, ExceptAddr, Buf, SizeOf(Buf));
DebugStr(Buf);
end;
end;
В библиотеке метод, возвращающий строку, выглядит так:
- Код: Выделить всё
procedure THtConnect.sc_DbName(var Dst); safecall;
begin
_Helper.AllocStr(PNChar(s2x(FDbName)), -1, Dst);
end;
В приложении, использующим библиотеку, так:
- Код: Выделить всё
procedure TCCbHandler.ConnectNotify(const HtConnect: IHtConnect; Operation: TConnectOperation);
var s: string;
begin
if Operation <> copStopped then Exit;
CheckLog(true);
if HtConnect = con then // в случае, например, HtConnect.Crash
con:= nil;
HtConnect.DbName(s);
WriteLn;
CWriteLn(['-- Disconnected from ', s], [caNote, caInfo]);
end;
То есть, приложение передаёт в библиотеку нетипизированную ссылку на строку, библиотека тут же возвращает эту ссылку и PChar на текст в основное приложение (хелперу),
который и занимается распределением памяти. В-общем, вариант колбэка. Один минус: получаются не функции, а процедуры. Если б можно было к интерфейсам хелперы объявлять..
