Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

IB SQL UDF [D6, IB6.x]


Nebula ©   (2002-07-05 14:51:00) 

Продолжение вопроса. Библиотеку создал, функция возвращает строку.

function MyUDF: string;
begin
result := "text";
end;

в IB описал.

DECLARE EXTERNAL FUNCTION NEBULA
RETURNS VARCHAR(1024) CHARACTER SET WIN1251
ENTRY_POINT "MyUDF"
MODULE_NAME "path\MyUDF.dll"

Как вызвать-то? select MyUDF не работает.


kaif   (2002-07-06 02:26:00) [1]

>2 Digitman
Спасибо за подробные объяснения. Особенно насчет способа вызова. Дело в том, что у меня вызовы stdcall срабатывают в Interbase и мои UDF-ы работают без видимых признаков проблем. Мне и в голову не пришло, что IB требует cdecl. Я по привычке вписал stdcall. Я знал разницу в принципах этих вызовов, но мне казалось, что все приложения Win32 как правило используют stdcall, по крайней мере все API. А вот, выясняется, что IB действует иначе...
Сейчас еще посмотрю, что у меня с NULL происходит (забыл проверить). То есть строковый NULL это просто пустая строка? Но ведь IB различает значения "" и NULL. Или это только при передаче параметров то же самое?


Digitman   (2002-07-05 18:28:00) [2]

Небольшое уточнение : правило передачи Null-параметров на строковые параметры не распространяется, и if Assigned(..) в таких случаях всегда даст True, потому как передается адрес ВРЕМЕННОГО блока памяти, содержащего на момент вызова UDF единственный символ - #0 (терминатор строки)


Digitman   (2002-07-05 18:22:00) [3]

>>фундаментального не знаю о передаче параметров по ссылке...

Эт точно) ... но - самокритично и вызывает неподдельное уважение.

Правило №1 (выучи как Отче Наш - очень поможет в дальнейшем):

абсолютно все факт.параметры передаются ядром IB-сервера в UDF ссылкой (указателем) на местоположение в АП сервера ВРЕМЕННОЙ КОПИИ оригинальных параметров.

Отсюда прямой вывод :

Объявление параметров в самой UDF должно делаться ,как минимум, двумя способами (возьмем для примера тот же Double)

1. var Value: Double
2. [const] Value: PDouble, где PDouble = ^Double;

[const] - необязательный спецификатор, разницы в том, есть он или отсутствует, в случае с UDF - абсолютно никакой

Соответственно, обращение из UDF к заначениям переданных параметров должно выглядеть след.образом :


1. SomeLocalVar := Value;
2. SomeLocalVar := Value^; вот оно, разыменование прямого указателя


Дабы не влипнуть в AV, следует еще и такую вещь всегда принимать во внимание : если передаваемый факт.параметр = Null, то в UDF передается nil, а проверить это во избежание AV оч.просто :

1. if Assigned(@Value) then ...

@ - это перекрытие действий компилятора по-умолчанию, который без "барана" в лучшем случае будет проверять на nil не переданную ссылку, а то что лежит фактически по этой ссылке, в худшем - вообще откажется компилировать

2. if Assigned(Value) then ...


Еще один важный момент : никаких stdcall в декларации экспортируемых ф-ций ! Только cdeclбудет работать правильно ! Почему ? Загляни в хэлп в топик "calling conventions" - сразу станут ясны различия с учетом того, что IB-ядро использует C-соглашения о вызовах и балансе стека при возврате из вызываемой cdecl-ф-ции


kaif   (2002-07-05 17:46:00) [4]

>2 Digitman.
Я знаю. Правда я думал, что FREE_IT используется исключительно для строк...

Кстати, спасибо за пример FormatDateTime. Он заработал.
Потом немного мучился с FormatFloat...
В конце концов удалось наконец принять в dll тип
DOUBLE PRECISION:

function FmtIBDouble(FmtStr: PChar; Value: Pointer): PChar; stdcall;
var
Tmp: String;
begin
try
Tmp:= FormatFloat(String(FmtStr), Double(Value^));
...и т.д.

Странно, но передача по ссылке (const Value: double) не работала. Я уже не первый раз с этим сталкиваюсь при работе с dll. Разве это не то же самое, что и разыменование указателя?
Видно я чего-то фундаментального не знаю о передаче параметров по ссылке...


Digitman   (2002-07-05 17:35:00) [5]

Небольшое замечание к kaif © (05.07.02 15:10)

спецификатор free_it вовсе не является обязательным при возврате чего-либо, в дан. случае - строки.

данный спецификатор требуется для указания IB-ядру сервера о необходимости автоматически освобождать блок памяти выделенный в теле UDF для передачи некоего (произвольного типа, в 1-ю очередь - строкового) возвращаемого параметра, после того, как значение возвращенного параметра буде считано из результирующего блока памяти. Если этого не сделать, возникнут утечки памяти и последствия работы сервера будут непредсказуемыми.


Johnmen   (2002-07-05 15:48:00) [6]

ib_udf.dll


Nebula   (2002-07-05 15:42:00) [7]

2Johnmen. С огромным удовольствием! Какую библиотеку использовать?


kaif   (2002-07-05 15:10:00) [8]

Нужно аллокировать память (GetMem) под строку, PChar возвращать, а не string и использовать FREE_IT в объявлении UDF. Функцию объявить как stdcall и экспортировать из dll (export).


Johnmen   (2002-07-05 15:03:00) [9]

1. dll должна лежать в соотв. месте
2. Может всетаки использовать уже существующие библиотеки ?


Val   (2002-07-05 15:02:00) [10]

а почему вы так ее вызываете? вы же select sum не пишите, к примеру?


Наверх

Титульная страница Поиск, карта сайта Написать письмо