Я разрабатываю это приложение в Дели 2009 с базой данных SQLite версии 3.7.9, доступ к которой осуществляется компонентами Zeos. Начну с ОК - я могу создать БД, если он не существует, создать таблицы и вставить записи - "нормальный материал". Существует небольшая таблица, содержащая последовательные параметры для подключения к некоторым старым устройствам, и обработчик последовательных сообщений должен быть проинформирован об изменениях параметров соединения, но компоненты Zeos не поддерживают события на SQLite.
Я посмотрел на SQLite API, и есть "Обратный вызов уведомления об изменении данных", поэтому я решил сделать это. Прототип установки:
void *sqlite3_update_hook(
sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
);
Итак, в Delphi я импортировал вызов DLL:
function sqlite3_update_hook(pDB:pointer;pCallback:pointer;aux:pointer): pointer; stdcall;
..
function sqlite3_update_hook; external 'sqlite3.dll' name 'sqlite3_update_hook';
.. и объявил пустой обратный вызов для тестирования:
function DBcallback(aux:pointer;CBtype:integer;CBdatabaseName:PChar;CBtableName:PChar;CBrowID:Int64):pointer; stdcall;
begin
end;
.. и называется настройкой:
sqlite3_update_hook(SQLiteHandle,@DBcallback,dmOilmon);
SQLiteHandle
- это указатель SQLiteHandle
sqlite3*
для базы данных, полученный из драйвера после подключения. dmOilmon
- это экземпляр DataModule, поэтому при правильной работе я могу вызывать некоторый метод из обратного вызова (да, я знаю, что обратный вызов находится в неизвестном потоке - я могу справиться с этим, я просто буду сигнализировать семафоры).
Хорошие новости: когда я запустил приложение, DBcallback
был вызван, по-видимому, успешно, после первой вставки. Плохая новость: через некоторое время приложение взорвалось "Слишком много исключений" и, как правило, окно процессора, полное "??" (иногда альтернатива - гибель системы и перезагрузка - Vista Ultimate 64). Разрыв в CBtype
CBrowID
, aux, CBtype
и CBrowID
были такими же ожидаемыми, но всплывающая подсказка отладчика показала, что CBdatabaseName
/CBtableName
PChars
указывает на строку китайских символов.
Я попытался проследить, откуда вызван обратный вызов - по какой-либо причине цепочка вызовов проходит по коду драйвера Zeos. Ломая там и перешагнув, я проверил указатель стека, и он будет таким же до и после обратного вызова.
Итак, я установил "пустой" обратный вызов, callback вызывается в ожидаемой точке, но с купе извращающих параметров, обратный вызов возвращается, откуда он пришел с SP правильно. Кажется, я все сделал правильно, но...: ((
Кто-нибудь видел это (или исправил его даже :)?
Можете ли вы предложить механизм, при котором непринужденно успешный обратный вызов может привести к тому, что приложение будет позднее генерировать рекурсивные исключения?
У кого-нибудь есть предложения по дальнейшей отладке?
Rgds, Martin
У вас есть проблемы с правильным переводом заголовка SQLite в Delphi и с привязкой:
stdcall
, но должен быть cdecl
.function DBcallback
должна быть procedure
. Поскольку void(*)(...)
является указателем на функцию C, возвращающую void
.PChar
, но должен быть PAnsiChar
. Для не-Unicode Delphi это может быть неважно, для Unicode Delphi это только правильный перевод.external 'sqlite3.dll'...
) в sqlite3.dll. Но ZeosLib использует динамическое связывание во время выполнения (LoadLibrary
& GetProcAddress
). Это может привести к проблеме "DLL hell", когда ваш EXE загружает один sqlite3.dll, а ZeosLib планирует загрузить еще один sqlite3.dll.