Подтвердить что ты не робот

DLL-ад с SQLite

Некоторые из наших пользователей получают проблему с версией sqlite.interop.dll, загружаемой во время выполнения, и это настоящий головной скребок.

Фон: Приложение WPF, созданное для AnyCPU, развернутое с SQlite.NET и sqlite.interop.dll версии 1.0.89. Мы развертываем dll x86 и x64 и используем загрузку задержки, включенную в SQLite. Это было хорошо до недавнего времени, когда мы начали получать несколько проблем со стороны пользователей, которые, как правило, недавно приобрели новые компьютеры Dell. Похоже, что существует более старая версия sqlite.interop.dll(v.1.0.80), которая каким-то образом загружается по сравнению с той, которую мы отправляем. Ошибка, которую мы получаем, является отсутствующей точкой входа, "sqlite3_changes_interop".

Что мы пробовали:

  • Измените настройку, чтобы просто скопировать соответствующую dll (x86/64) в тот же каталог, что и исполняемый файл во время установки (т.е. отдельные папки x86/x64). Это означает, что мы больше не используем загрузку задержки, так как правильная dll доступна в исполняемом каталоге (хотя мы явно не отключили механизм загрузки задержки в sqlite.net). Это не устраняет проблему.

  • Явно загружаю sqlite.interop.dll, когда приложение загружается. Опять же, это, похоже, не устраняет проблему.

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

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

На самом деле это застряло, поэтому любая помощь будет большой.

Кроме того, в качестве окончательного варианта - я мог бы рассмотреть вопрос о возврате к той же версии 1.0.80, чтобы мы не получили эту проблему. Кто-нибудь знает, где мы могли бы использовать более старые версии sqlite.net и sqlite.interop.dll?

Изменить - дополнительная информация:

Столкновение вызвано копией sqlite.interop.dll версии 1.0.80, установленной с помощью Dell Backup and Recovery. Это устанавливается на всех новых компьютерах Dell, и пользователи, которые устанавливают наше программное обеспечение на такой машине, все это испытывает. Это программное обеспечение Dell также использует System.Data.SQLite.dll.

Правильная версия sqlite.interop.dll находится в том же каталоге, что и наш исполняемый файл, и все, что я понимаю о загрузке dll, предполагает, что это должно быть загружено в предпочтении.

Хотя мы еще не смогли воспроизвести проблему локально, похоже, что неправильная версия interop.dll не находится на пути. Кроме того, утилита резервного копирования Dell запускается автоматически при запуске. Кто-нибудь знает о каком-либо возможном механизме, с помощью которого это может быть связано с загрузкой запросов DLL и обслуживанием неправильного файла?

Текущая линия мышления заключается в том, что мы могли бы создать собственную System.Data.SQLite.dll и изменить код загрузки interop на специально именованную версию (например, sqlite.interop.1.0.89.dll). Нехорошее решение идет вперед, но..

4b9b3361

Ответ 1

Наше приложение имеет ту же проблему. Как вы упомянули, проблема в том, что Dell Backup and Recovery устанавливает расширение оболочки, которое использует старые версии нескольких популярных DLL. Они играют в ад с любым приложением, которое запускает диалоговые окна файлов, а также использует эти библиотеки, потому что расширения оболочки загружают свои DLL в ваш AppDomain. Единственное решение, которое мы имеем до сих пор, - это сообщить пользователям удалить Dell Backup and Recovery.

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

Интересно, что Dell Backup and Recovery является повторным нарушителем; он также так же нарушает QT5. Рекомендованное решение от ребята QT состоит в том, чтобы скомпилировать вашу библиотеку QT под другим именем с параметром -qtnamespace [name]. Мы могли бы установить что-то подобное с помощью system.data.sqlite, но тогда нам пришлось бы скомпилировать нашу собственную версию.

Microsoft знает о проблеме, но отказалась ее исправить.

Я бы хотел, чтобы ребята Dell внедрили расширение оболочки как это.

Portroit Pro, SONAR, и AutoDesk решение этой проблемы - также удалить Dell Backup and Recovery.

Типичная трассировка стека проблемы выглядит в нашем приложении:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 
at System.Data.SQLite.UnsafeNativeMethods.sqlite3_open_interop(Byte[] utf8Filename, Int32 flags, IntPtr& db) 
at System.Data.SQLite.SQLite3.Open(String strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, Int32 maxPoolSize, Boolean usePool) 
at System.Data.SQLite.SQLiteConnection.Open() 
at STCommonShellIntegration.DataShellManagement.CreateNewConnection(SQLiteConnection& newConnection) 
at STCommonShellIntegration.DataShellManagement.InitConfiguration(Dictionary`2 targetSettings) 
at DBROverlayIcon.DBRBackupOverlayIcon.initComponent()

Поэтому в ответ на комментарий Track, если вы хотите обнаружить эту конкретную проблему и дать пользователям специальное уведомление, вы можете сделать что-то вроде этого:

AppDomain.CurrentDomain.UnhandledException += UEHandler;
//...
static void UEHandler(object sender, UnhandledExceptionEventArgs e){
  var ex = e.ExceptionObject as Exception;
  if( ex.ToString().Contains( "DBROverlayIcon" ){
    //show some dialog here telling users to uninstall DBaR
  }
}

Ответ 2

SQLite.Interop.dll загружается сложным способом.
Используя любой отражатель, вы можете самостоятельно изучить метод UnsafeNativeMethods.Initialize() в System.Data.SQLite.dll.
Некоторые примечания, чтобы продемонстрировать, что можно получить что-то интересное путем отражения (версия 1.0.89):

  • Если SQLite.Interop.dll помещается в базовый каталог - он будет загружен
  • Переменные среды PreLoadSQLite_BaseDirectory и PreLoadSQLite_UseAssemblyDirectory могут влиять на процесс загрузки.
  • SQLite.Interop.dll можно искать в заранее определенных подпапках (x86, x64, Win32, Itanium, WinCE)
  • Trace.WriteLine вызывается для уведомления выбранного пути (не всегда)

Исходный код также доступен.

Ответ 3

Мы имеем дело с этой точной проблемой, и решение, которое мы нашли, - использовать пакет в комплекте с сайта System.Data.SQlite, а не пакет из nuget: https://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki

В комплекте DLL объединены объединенные и неуправляемые сборки, поэтому нет необходимости динамически загружать правильный Sqlite.Interop.dll, поэтому у вас нет проблемы с конфликтующими версиями в appdomain.

При использовании собранной сборки вам нужно включить свою собственную логику в установщик приложения, чтобы решить, какую DLL для копирования (x86 или x64).

У нас больше не возникало проблем с конфликтующими версиями, поскольку мы использовали собранную сборку.