Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Firebird, Interbase > Соглашение вызова в UDF-библиотеке


Автор: Sister 17.5.2006, 01:55
Проблема вот в чем. Создал UDF dll-ку, сервером функция из нее вызывается, возвращаемое значение адекватно получаему параметру, но вот сам параметр не передается (точнее передается что-то вроде его адреса).

UDF: Тип параметра - INTEGER, возвращает CSTRING(30).

Тестировал dll-ку в Delphi, все получается нормально, когда соглашения вызова совпадают и в библиотеке и в программе, но что касается сервера БД, то он при некоторых соглашниях вызова, установленных в библиотеке, отказывается работать. Какое соглашение должно быть? 

Автор: TheCetus 17.5.2006, 09:44
DECLARE EXTERNAL FUNCTION CET_POSEX
  CSTRING(250), CSTRING(32767), INTEGER
RETURNS
  INTEGER BY VALUE
ENTRY_POINT 'Cet_PosEx' MODULE_NAME 'cet_udf';

вроде на форуме где то лежала статья как UDFы писать

Добавлено @ 09:45 
DECLARE EXTERNAL FUNCTION CET_GET_PARAMITEM
  CSTRING(1), CSTRING(32767), INTEGER
RETURNS
  CSTRING(250) FREE_IT
ENTRY_POINT 'Cet_Get_ParamItem' MODULE_NAME 'cet_udf';

Добавлено @ 09:47 
а еще лучше покажи скрипты регистрации функций, код самих функций и параметры при которых все падает
 

Автор: Sister 18.5.2006, 21:14
Код dll:

library Project2;
uses SysUtils, Classes;
{$R *.res}

function GetNameOfPeriod(days: integer): PChar; export;
begin
//остальной код, первым делом проверяю days - оно вообще не то, которое передается
end;

exports  GetNameOfPeriod;
begin end.

Скрипт регистрации:
DECLARE EXTERNAL FUNCTION u_getname
    INTEGER
RETURNS CSTRING(30)
ENTRY_POINT 'GetNameOfPeriod' MODULE_NAME 'Project2';

Любой параметр типа integer передается неверно, например, так:

SELECT rdate, content, tim, u_getname(tim) 
FROM requests;
где tim определен как integer.

Что интересно, так это то, что при соглашении вызова cdecl правильно передаются строки CSTRING(XXX), но неправильно - числа. А если соглашение принимается таким, какое оно по умолчанию, то вообще ничего из них не передается верно (пробовал только строки и числа).
 

Автор: TheCetus 19.5.2006, 12:10
Код

library Cet_UDF;

function malloc(Size: Integer): PChar; cdecl; external 'msvcrt.dll';


function Cet_Char(a:byte) : PChar; cdecl export;
var
  s : string;
begin
  s := Chr(a);
  Result := malloc(2);
  StrPCopy(Result, s);
end;


Exports
  Cet_Char;

End.



Код

DECLARE EXTERNAL FUNCTION CET_CHAR
  INTEGER
RETURNS
  CSTRING(10) FREE_IT
ENTRY_POINT 'Cet_Char' MODULE_NAME 'cet_udf';


Добавлено @ 12:14 
у меня при сипользовании cdecl все нормально передается 

Автор: Sister 19.5.2006, 20:55
2TheCetus: передаешь INTEGER, а принимаешь byte. Почему? 
Хотя это и не имеет большого значения, я думаю. 

Автор: Sister 19.5.2006, 21:44
Показательный пример:
Код

library Project2;

uses  SysUtils,  Classes;

{$R *.res}

function ReturnParam(a: integer): integer; cdecl; export;
begin
Result:=a;
end;

exports  ReturnParam; 

begin end.


Скомпилированная dll помещается в ...Firebird_1_5\UDF
Скрипты БД:
Код

CREATE TABLE REQUESTS (
    ID       INTEGER NOT NULL,
    RDATE    DATE,
    CONTENT  VARCHAR(50),
    TIM      INTEGER,
    ID_BR    INTEGER,
    ID_P     INTEGER
);


DECLARE EXTERNAL FUNCTION "u_ReturnParam"
    INTEGER
RETURNS INTEGER BY VALUE
ENTRY_POINT 'ReturnParam' MODULE_NAME 'Project2';


Результаты следующего запроса:
       
Код

SELECT tim, "u_ReturnParam"(tim)
       FROM requests;


TIM  u_ReturnParam  
  3     17 692 540  
  5     17 692 540  
  2     17 692 540  
  7     17 692 540  
  7     17 692 540  
  2     17 692 540  
  3     17 692 540  
  1     17 692 540  
  3     17 692 540  
  2     17 692 540  
  3     17 692 540
   

Автор: TheCetus 22.5.2006, 09:00
короче, вот решение:


Код


function ReturnParam(var a: integer): integer; cdecl; export;
begin
Result:=a;
end;



все параметы передаваемые по значению должны именно так и передаваться )
т.е. параметры типа integer, byte должны быть описаны с VAR


P.S. Посмотрел, у меня в проекте функция Cet_Char не использовуется, поэтому баг не заметил сразу 

Автор: Sister 28.5.2006, 03:09
Цитата

все параметы передаваемые по значению должны именно так и передаваться

А уверен, что по значению, ведь var - это передача по ссылке.

 Я пробовал так делать, но не получалось может быть из-за того, что я изменял и соглашение и писал var безсистемно, не проверив всех вариантов, один из которых мог оказаться удачным. 

И чем параметры integer и byte так выделяются?

И еще - чтобы передавать параметр не по ссылке, надо в объявлении функции в БД после указания его типа писать BY VALUE ?

Так или иначе, это мне уже не нужно, но теперь просто интересно узнать, как все это правильно делается. 

Автор: TheCetus 29.5.2006, 09:22
точно, описАлся... по ссылке...

вот работающий код UDF функции
Код

function Cet_PosEx(aSubStr : PChar ;aStr : PChar; var Idx : integer) : integer; cdecl export;
begin
  Result := PosEx(aSubStr, aStr, Idx);
  Idx := Result + 1;
end;


Код

DECLARE EXTERNAL FUNCTION CET_POSEX
  CSTRING(250), CSTRING(32767), INTEGER
RETURNS
  INTEGER BY VALUE
ENTRY_POINT 'Cet_PosEx' MODULE_NAME 'cet_udf';

значение возвращается по значению, а не по ссылке
передается по ссылке
строки передаются как PChar...

вприницпе тут где то была статья как писАть UDF функции, там все достаточно хорошо расписано...
свою библиотеку писал по этой статье 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)