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

Я разрабатываю это приложение Delhi 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 - это указатель sqlite3* для базы данных, полученной из драйвера после подключения.dmOilmon является экземпляром DataModule, так что при правильной работе я могу вызывать некоторый метод из обратного вызова (да, я знаю, что обратный вызов находится в неизвестном потоке - я могу справиться с этим, я просто буду сигнализировать семафоры).

Хорошая новость: когда я запустил приложение, DBcallback вызывался, как правило, успешно, при первой вставке.Плохая новость: некоторое время спустя приложение взорвалось «Слишком много исключений» и, как правило, окном процессора было полно «??» (случайной альтернативой была смерть системы и перезагрузка - Vista Ultimate 64).Прерывание в обратном вызове, aux, CBtype и CBrowID были все как ожидалось, но подсказка отладчика показала, что CBdatabaseName / CBtableName PChars указывает на строку китайских символов ..

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

Итак, я установил «пустой» обратный вызов, обратный вызов вызывается в ожидаемой точке, но с купеиз хитроумных параметров обратный вызов возвращается туда, откуда он пришел с правильным SP.Кажется, я все сделал правильно, но ...: ((

Кто-нибудь видел это, (или даже исправил это :))?

Можете ли вы предложить механизм, с помощью которого можно успешно осуществить обратный вызов?Можно ли заставить приложение позднее генерировать рекурсивные исключения?

У кого-нибудь есть предложения по дальнейшей отладке?

Rgds, Martin

1 Ответ

2 голосов
/ 20 ноября 2011

У вас проблемы с правильным переводом заголовка 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 ад», когда ваш EXE загружает один файл sqlite3.dll, а ZeosLib планирует загрузить другой файл sqlite3.dll.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...