Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.03.18;
Скачать: CL | DM;

Вниз

UDF и Interbase   Найти похожие ветки 

 
Dimedrol ©   (2002-02-18 15:33) [0]

Коллеги, поделитесь опытом плиз.
Узнал я, что можно на Kylix писать *.so-библиотеки
и подшивать их к Interbase.
Попробовал - ок! ;-)
НО, остались некоторые непонятки:
Делаю SO :

library testudf;

uses
SysUtils, Classes;

function Fun1(n:Integer): PChar; cdecl;
var sBuf:string;
i:integer;
begin
if n>=0 then result:="BIGger" else result:="smaller";
end;

exports Fun1;

begin
end.


Подцепляю...


DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS CSTRING(32)
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";


OK.
Вызываю :

select Fun1(5) from rdb$database;


Вот только почему-то все что я ни передаю -
все возвращает - "smaller"
То есть и "5" и "-3" и "0" это все, типа, меньше нуля...

Что не так ? :-/


 
Digitman ©   (2002-02-18 16:20) [1]

1. IB все параметры в UDF передает по ссылке на временную копию параметра в TLS кодового потока, ассоциированного с клиентским соединением.

2. Для возврата UDF-результата типа PChar необходимо (в общем случае) выделять память под него. По соглашениям IB, для этого необходимо исп-ть мультипоточный менеджер памяти от MSVC : msvcrt.dll

C учетом этих требований твой код должен выглядеть примерно так :



function malloc(Size: Integer): Pointer; cdecl; external "msvcrt.dll";

function Fun1(var n:Integer): PChar;
begin
Result := malloc(8);
if n>=0 then
StrCopy(result, "BIGger")
else
StrCopy(result, "smaller");
end



 
Digitman ©   (2002-02-18 16:26) [2]

P.S. UDF может возвращать в выделенной ей самой памяти (см.malloc) не только строковые результаты, но и любых допустимых в IB типов. При этом важно лишь декларировать в IB-скрипте такие UDF с флагом FREE_IT


 
Dimedrol ©   (2002-02-18 16:48) [3]

А то, что я делаю это под Linux,
не накладывает никаких ограничений\отличий ?


 
Digitman ©   (2002-02-18 16:53) [4]

не буду одназначно утверждать, но - не должно как бы...
почитай док-цию к IB под Linux


 
Dimedrol ©   (2002-02-18 17:07) [5]

Хмммм....
ну допустим...
А как в таком случае мне вернуть из функции
ЧИСЛО ?
Просто число.
ТО есть есть >0 то возвращаем "1"
в противном случае "-1" ?


 
Digitman ©   (2002-02-18 17:22) [6]

под "простым числом" что понимать ? число из "решета Эратосфена" ?

или - Integer, целочисленный знаковый результат, как это принято у программеров ?)

вариантов минимум 2 :

1.

function Fun1(var n:Integer): Integer;
begin
if n > 0 then
Result := 1
else
Result := -1
end;

DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer BY VALUE
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";


1.

function Fun1(var n:Integer): Integer;
begin
if n > 0 then
Result := 1
else
Result := -1
end;

DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer BY VALUE
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";


2.

function Fun1(var n:Integer): PInteger;
begin
Result := @n;
if n > 0 then
Result^ := 1
else
Result^ := -1
end;

DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";



Учти, что в приведенные примерные варианты UDF нельзя передавать неинициализированнй параметр N (имеющий на момент вызова NULL-значение). Иначе неизбежно исключение AV с падением коннекта или всего сервера. В приведенных мной примерах для простоты я не обрабатываю такую ситуацию. В идеале же это необходимо делать обязательно, во избежание генерации в теле UDF любых "непогашенных" исключений, в первую очередь - AV.


 
Dimedrol ©   (2002-02-18 17:25) [7]

Ооо !
Заработало! ;-)
Вот что я написал на Kylix:


uses
SysUtils,
Classes;

const
libcmodulename = "libc.so.6";

Эту фигню скопировал из SysInit.pas
Оттуда же - способ описания функции Malloc

И далее...


function malloc(Size: LongWord): Pointer; cdecl;
external libcmodulename name "malloc";

function Fun1(var n:Integer): PChar;
begin
Result := malloc(8);
if n>=0 then
StrCopy(result, "BIGger")
else
StrCopy(result, "smaller");
end;



Так, как я понял, чтобы вернуть число,
мне нужно "малочить" например 4 байта для Integer ?!



 
Digitman ©   (2002-02-18 17:26) [8]

вот тебе еще одно решение, неэффективное в данном контексте, но, тем не менее, имеющее "право на жизнь" :


function Fun1(var n:Integer): PInteger;
begin
Result := malloc(sizeof(integer));
if n > 0 then
Result^ := 1
else
Result^ := -1
end;

DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer FREE_IT
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";



 
Digitman ©   (2002-02-18 17:29) [9]

совершенно необязательно "маллочить" в каждом случае : это зависит от невозможности вернуть результат иным способом, без явного выделения памяти под него


 
Digitman ©   (2002-02-18 17:37) [10]

а способов вернуть результат из UDF в IB - просто куча ) просто в каждом конкретном случае нужно полное понимание механизма передачи конкретных параметров и приема результата


 
Dimedrol ©   (2002-02-18 17:40) [11]

Такс... ;-) Результаты тестирования :

function Fun1(var n:Integer): Integer;
begin
if n > 0 then
Result := 1
else
Result := -1
end;


Подшитая так :

DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";


или так :

DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer BY VALUE
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";


не пашет. ;-(

Все время - Result := 1

Пробую дальше...


 
Dimedrol ©   (2002-02-18 17:51) [12]

Ну вот... работает эта :

function Fun1(var n:Integer): PInteger;
begin
Result := @n;
if n > 0 then
Result^ := 1
else
Result^ := -1
end;

Описанная как :

DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";


Еще 2 небольших вопросика остались...

1. Почему в описании функции
нужно писать именно - ( var n:Integer) ?
Разве нельзя просто (n:Integer) ?

2. И зачем в начале ф-ции мы делаем Result := @n;
Вроде ф-ция и так поинтер ( ): PInteger;)
Зачем еще это ? 8-\


 
Digitman ©   (2002-02-18 18:22) [13]

Вариант в
Dimedrol © (18.02.02 17:40)

описанный как

DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer BY VALUE
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";

должен работать однозначно !


>>1. Почему в описании функции
нужно писать именно - (var n:Integer) ?
Разве нельзя просто (n:Integer) ?

Нельзя. var = по ссылке.
то, что и передает IB в реальности.
и ты в этом убедился на одном из работающих у тебя примеров

>>2. И зачем в начале ф-ции мы делаем Result := @n;
Вроде ф-ция и так поинтер (): PInteger;)
Зачем еще это ? 8-\

IB выделил врем.память под параметр N, записал туда значение и передал адрес этого параметра тебе в UDF. После приема результата работы UDF он уничтожит этот временный параметр, не контролируя его содержимое. Но ! Поскольку ты передаешь рез-т по ссылке, указывая IB адрес, где рез-т хранится, IB возьмет его по указ.адресу, прежде чем уничтожит свои параметры. А указ.адрес совпадает (Result:= @N !!) с адресом одного из параметров - и ничто не мешает воспользоваться этим фактом ! Все корректно , все довольны, лишних операций с менеджером памяти удается избежать : IB дал тебе врем.буфер со знач.параметра и ответственен за уничтожение буфера после завершения вызова UDF, ты же воспользовался им (буфером) не только для получения зн-я параметра, но и для возврата рез-та через этот буфер !


 
Dimedrol ©   (2002-02-18 18:46) [14]

Мда...
К стати, если передавать строку внутрь,
то Var ставить не нужно.
Только вот сейчас проверил.
Наверное потому, что при передаче Pchar
как параметра мы и так передаем ссылку.
Да ?!


 
Digitman ©   (2002-02-18 18:47) [15]

Да. PChar есть указатель, а указатель - это и есть ссылка


 
Dimedrol ©   (2002-02-18 18:50) [16]

Ну что-ж...
БОЛЬШОЕ спасибо за помошь !
Ты мне очень помог сегодня ! 8-)


 
Digitman ©   (2002-02-18 18:51) [17]

не за что)



Страницы: 1 вся ветка

Текущий архив: 2002.03.18;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.012 c
1-57442
Компонент
2002-03-03 22:39
2002.03.18
Подскажите, есть ли компонент, чтобы сделать свой собственный Object Inspector?


14-57503
Knight
2002-01-30 17:18
2002.03.18
СМС с вашегорабочего стола - где-то видел


3-57273
Gromozeka
2002-02-15 07:13
2002.03.18
FormCreate


1-57347
vopros
2002-03-04 11:59
2002.03.18
Как отправить в Word текст в колонтитулы?Через OLE автоматизацию?


1-57402
Beeper
2002-02-28 21:50
2002.03.18
Как определить в проекте, какая из форм будет активной?