Обратный вызов SQLite вызывает рекурсивные исключения после успешного возврата

-4

Я разрабатываю это приложение в Дели 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

  • 0
    Вы пытались изменить параметры функции обратного вызова CBdatabaseName и CBtableName на PAnsiChar? IIRC SQLite ожидает здесь ансичары.
  • 0
    Я попробую это сейчас. Обновление - я только что попытался запустить EXE вне отладчика - он был остановлен ОС с DEP-боксом! Похоже, что адрес возврата поврежден, но где?
Показать ещё 6 комментариев
Теги:

1 ответ

2
Лучший ответ

У вас есть проблемы с правильным переводом заголовка SQLite в Delphi и с привязкой:

  1. Не stdcall, но должен быть cdecl.
  2. Ваша function DBcallback должна быть procedure. Поскольку void(*)(...) является указателем на функцию C, возвращающую void.
  3. Не PChar, но должен быть PAnsiChar. Для не-Unicode Delphi это может быть неважно, для Unicode Delphi это только правильный перевод.
  4. Вы используете динамическую компоновку времени компиляции (external 'sqlite3.dll'...) в sqlite3.dll. Но ZeosLib использует динамическое связывание во время выполнения (LoadLibrary & GetProcAddress). Это может привести к проблеме "DLL hell", когда ваш EXE загружает один sqlite3.dll, а ZeosLib планирует загрузить еще один sqlite3.dll.
  • 0
    Спасибо! Я узнал о cdecl, когда переместил вызов установки sqlite3_update_hook в собственную процедуру и вызвал ее - возврат взорвался. Переход на cdecl позволил процедуре работать нормально, поэтому я также изменил функцию обратного вызова на cdecl. Кажется, что не имеет значения, объявлен ли обратный вызов функцией Delphi или proc - это не меняет симптомов.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню