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

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

Установил Yaffil_877ss. Не работает UDF. [D6, IB6.x]


Страницы:   1 2

kaif ©   (2004-01-15 17:45:00) 

Работал на Yaffil_821ss. Установил Yaffil_877ss.
Перестала вызываться моя функция из UDF.
Ошибка "function FROMAT_DATETIME could not be matched"
При этом "стандартные функции IB" работают.
---------------------
DECLARE EXTERNAL FUNCTION FORMAT_DATETIME
CSTRING(30) CHARACTER SET WIN1251, TIMESTAMP
RETURNS CSTRING(30) CHARACTER SET WIN1251 FREE_IT
ENTRY_POINT "FmtIBDateTime" MODULE_NAME "alg_udf";
эта функция не работает (она моя)
---------------------
DECLARE EXTERNAL FUNCTION strlen
CSTRING(32767)
RETURNS INTEGER BY VALUE
ENTRY_POINT "IB_UDF_strlen" MODULE_NAME "ib_udf";
эта функция работает (она стандартная)
-----------------------
Судя по тексту ошибки, функция не находится по имени.
----------------------------
То, что я нашел в FAQ я не очень понимаю:

Yaffil начиная со сборки 867 компилируется MSVC7. Это означает, что теперь используется сервисная библиотека msvcr7.dll, а не msvcrt.dll как раньше (msvc6). В этой библиотеке есть функция malloc, отвечающая за аллокирование памяти.

Таким образом, если ваши udf содержат фунции с free_it, которые напрямую аллокируют память вызовом функции из msvcrt, или наоборот, делают это правильно через ib_util.dll но от сервера IB или FB, в результате получается что ваша udf использует один менеджер памяти, а сервер - другой. Что и приводит ко всяким проблемам с работоспособностью сервера.

Убедитесь, что ваша функция использует вызов не malloc, а ib_util_malloc, и что ib_util.dll имеет версию Yaffil не ниже 865 сборки (а также что на компьютере нет других ib_util.dll, которые могут быть найдены операционной системой ранее правильной ib_util.dll).


Я как-то работал с MSVC7 и мне кажется, что там имена в dll как-то странно приходилось давать (со знаком подчеркивания или как - не помню). К тому же я понимаю, что мне нужно что-то менять в аллокировании памяти (но это уже видимо другая ошибка, которая пока не проявляется, так как не работает сама функция). Подозреваю, что я вообще должен поменять аллокирование памяти, но как правильно - не знаю. Мой текст функции привожу:

function FmtIBDateTime(FmtStr: PChar; var Value: TISC_QUAD): PChar; cdecl; // free_it
var
Tmp: String;
begin
try
Tmp:= FormatDateTime(StrPas(FmtStr), QuadToDate(Value));
GetMem(Result, Length(Tmp)+1);
try
StrCopy(Result, PChar(Tmp));
except
FreeMem(Result);
raise;
end;
except
Result:= nil;
end;
end;


------------
Буду благодарен за любые разъяснения и любую помощь в правильном написании этой функции.


kaif   (2004-01-15 23:45:00) [1]

В общем, теперь это выглядит так:

function ib_util_malloc(l: integer): pointer; cdecl; external "ib_util.dll";

function FmtIBDateTime(FmtStr: PChar; var Value: TISC_QUAD): PChar; cdecl; // free_it
var
Tmp: String;
begin
Tmp:= FormatDateTime(StrPas(FmtStr), QuadToDate(Value));
Result := ib_util_malloc(Length(Tmp)+1);
StrCopy(Result, PChar(Tmp));
end;

А в декларации функции, соответственно, FREE_IT

И все в таком духе. Работает. Надеюсь, теперь правильно.
Еще раз спасибо всем.


kaif   (2004-01-15 22:24:00) [2]

2 Vlad © (15.01.04 20:46) [23]
OK. Спасибо большое. Особеннно за эксперимент с GetMem.
Всем спасибо. Век живи - век учись. Пойду исправлять.


Vlad   (2004-01-15 20:46:00) [3]

Кстати, для полной ясности решил провести небольшой тест.
Использовал UDF, где аллокировал память под Result с помощью GetMem
На небольших таблицах работает четко, но как только пробую делать апдейт с помощью этой функции на таблице с 4 млн записей, то примерно на втором миллионе выдает ошибку....
Так что вот... jack128 © был прав. Выделять память лучше тем же менеджером, который потом будет освобождать.


Vlad   (2004-01-15 20:23:00) [4]


> что мне использовать вместо FreeMem?

Вместо Free_Mem сервер будет делать FREE_IT сам, если указана данная опция в UDF


Vlad   (2004-01-15 20:21:00) [5]

Да, судя по всему ты прав, последний абзац именно это и означает.

Если вы сами аллокируете......
имелось ввиду, что под любые другие переменные (не Result)


kaif   (2004-01-15 20:21:00) [6]

2 jack128 © (15.01.04 19:45) [13]
я правильно тебя понял, что на всякий пожарный мне нужно переписать функцию и вместо GetMem использовать ib_util_malloc ?
Но если это так, то что мне использовать вместо FreeMem?
Или мне вообще выкинуть конструкцию с try .. except ?
А если у меня будут какие-то рискованные вещи и нужно будет использовать try .. except, что мне применять в качестве FreeMem ?
У меня такое ощущение, что народ что-то умалчивает. Или есть еще функция free_it в этой dll и надо именно ее юзать?


jack128   (2004-01-15 20:19:00) [7]

Ну да. Я привел этот пример, что бы показать, что выделять память под переменную, которая НЕ будет передаваться на сервер можно любым менеджером..


Vlad   (2004-01-15 20:15:00) [8]


> jack128 © (15.01.04 20:09) [17]

Да, сорри, temp - это string, поэтому Delphi сам выделяет и освобождает память.
Но Temp в данном случае не причем, не она же на сервер передается. Речь идет о переменной Result, а под нее автор ручками выделяет память.


jack128   (2004-01-15 20:09:00) [9]


> Vlad © (15.01.04 20:04) [16]
Вообще не понял. Кто ж тогда память выделяет? (под temp)


Vlad   (2004-01-15 20:04:00) [10]


> jack128 © (15.01.04 19:59) [15]

Кстати твои комментарии:

// память под temp аллокирует дельфийский менеджер
// Тут он осводождает память из под Temp.


не совсем верны. Точнее сказать они будут верны если ты сам, собственноручно подключешь в uses менеджер ShareMem.
Без этого, память не будет самани выделяться ни освобождаться. А выделяет автор ее ручками (GetMem), освобождает сервер (как показывает практика - успешно). Так что все справедливо.


jack128   (2004-01-15 19:59:00) [11]


> Если память выделяет один менеджер, а освобождает другой,
> это совершенно не значит что возникнет ошибка
не так мыслишь.
Если память выделяет один менеджер, а освобождает другой, это не значит, что ошибка НЕ возникнет ;-). А так как во внутрености менаджеров мы залесть не можем(или можем, но ВЛО-О-ОМ :-))), то лудше не рисковать.


Vlad   (2004-01-15 19:53:00) [12]


> jack128 © (15.01.04 19:45) [13]

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


jack128   (2004-01-15 19:45:00) [13]


> Теперь можно использовать GetMem так как я использую, то
> есть с последующим FREE_IT ?
> Я так понимаю, что по логике нельзя...
Правильно понимаешь.


> Тогда о чем речь в последнем абзаце?
Речь об этом

> function FmtIBDateTime(FmtStr: PChar; var Value: TISC_QUAD):
> PChar; cdecl; // free_it
> var
> Tmp: String;
> begin
> try
> Tmp:= FormatDateTime(StrPas(FmtStr), QuadToDate(Value)); // память под temp аллокирует дельфийский менеджер памяти
> GetMem(Result, Length(Tmp)+1);
> try
> StrCopy(Result, PChar(Tmp));
> except
> FreeMem(Result);
> raise;
> end;
> except
> Result:= nil;
> end;
> end; // Тут он осводождает память из под Temp.
В этом нет ничего странного так как память выделяется/освобождается ПАРНЫМИ функциями.(одним и тем же менаджером памяти)

Поэтому же для free_it результатов память нужно выделять ОБЯЗАТЕЛЬНО c помощью ib_util_malloc, так как сервер осводождает память в помоью парной её функции. То есть выделение/освобождение памяти происходит с помощью одного менаджера памяти.


Vlad   (2004-01-15 19:43:00) [14]


> Я так понимаю, что по логике нельзя... Тогда о чем речь
> в последнем абзаце?

Да фигня всё это. С чего ты взял что GetMem нельзя использовать ?
То что ты прочитал в FAQ означает то, что нельзя использовать ф-цию malloc (вместо нее ib_util_malloc). А GetMem никто не отменял :-)


kaif   (2004-01-15 19:28:00) [15]

Дико извиняюсь!!!
Действительно, при деинсталляции прежнего Yaffil у меня удалилась моя dll из каталога UDF. Так как тот инсталлятор я сам писал и заодно включил свою dll в инсталляцию. :(
Так что UDF заработали. Но что касается новой mvcrt это меня озадачило.

2 Desdechado © (15.01.04 18:37) [3]
Ошибка "function FORMAT_DATETIME could not be matched". Я опечатался, набирая текст от руки.

2 jack128 © (15.01.04 19:06) [8]
Я этот FAQ прочитал только сегодня. Я и не знал, что нельзя использовать дельфийский менеджер памяти GetMem. Скорее всего, я с самого начала делал что-то неправильно. Но так как это работало, а утечки ресурсов я не наблюдал, я думал, что действую верно... Видимо, жестоко ошибался.

2 Vlad
Большое спасибо за ссылку!!!!!!!!!!!!

Как правильно аллокировать память для UDF с FREE_IT?

Нужно делать следующим образом - начиная с InterBase 5.0 в комплект сервера входит ib_util.dll содержащая функцию ib_util_malloc. Ее объявления для C и Pascal есть в каталоге include:

ib_util.h - extern void * ib_util_malloc (long);
ib_util.pas - function ib_util_malloc(l: integer): pointer; cdecl; external "ib_util.dll";

Для аллокирования памяти и FREE_IT нужно использовать эту функцию. Поскольку сервер сам освобождает занятый участок памяти, функция для освобождения памяти в этой библиотеке не предусмотрена.

При этом ib_util.dll должна находиться в PATH или рядом с вашей dll UDF. Позаботьтесь о том, чтобы на сервере не было двух или более ib_util.dll от разных серверов. В противном случае возможна некорректная работа сервера, его падение или что еще хуже - повреждение базы данных.

Использование ib_util является 100% переносимым, т.к. эта библиотека является стандартной для Interbase (всех версий выше 5.0), Firebird и Yaffil и поставляется под все платформы.

Если вы сами аллокируете/деаллокируете память внутри UDF (с FREE_IT или без), то можете для этих целей использовать любые функции, в том числе getmem/freemem в Delphi.


Однако последний абзац меня опять озадачил.
Может, кто-то прояснит? Теперь можно использовать GetMem так как я использую, то есть с последующим FREE_IT ?
Я так понимаю, что по логике нельзя... Тогда о чем речь в последнем абзаце?


jack128   (2004-01-15 19:20:00) [16]


> Судя по тексту ошибки, функция не находится по имени.
как функция экспортируется? Имена функций в dll - регистрочувствительны.


Vlad   (2004-01-15 19:10:00) [17]


> jack128 © (15.01.04 19:06) [8]


> То что проблем нету сейчас не означает. что их небудет
> потом(например в новой версии Delphi)

Скорее в новой версии Yaffil.
На самом деле ошибка совершенно не связана с реализацией функции. Судя по тексту ошибки, и первой моей ссылке из [1], до выполнения функции дело вобще не доходит.


jack128   (2004-01-15 19:06:00) [18]


> Vlad © (15.01.04 18:47) [7]


> UDF все время GetMem пользовался, проблем еще ни разу не
> было.
То что проблем нету сейчас не означает. что их небудет потом(например в новой версии Delphi). Меня вообще то больше интересует зачем kaif привел эту цитату, если сам не соблюдается данные в ней рекомендации ;-)


Vlad   (2004-01-15 18:47:00) [19]


> jack128 © (15.01.04 18:44) [6]

Максимум что может быть, так это ошибка Invalid Pointer Operation при выполнении этой ф-ции, хотя лично я в Yaffil"овских UDF все время GetMem пользовался, проблем еще ни разу не было.


jack128   (2004-01-15 18:44:00) [20]


> А чего тут понимать ? Выделение пямяти под Result, проблема
> явно не в этом.
внимательно считываемся в цитату кайфа, насчет того какой функцией должна выделяться память под free_it результат.


Страницы:   1 2

Наверх

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