2015-06-14 3 views
18

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

Фон: Приложение 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».

То, что мы пытались:

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

  2. При загрузке приложения явная загрузка sqlite.interop.dll. Опять же, это не похоже на проблему.

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

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

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

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

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

столкновение вызвано копией sqlite.interop.dll версии 1.0.80, который установлен с Dell резервного копирования и восстановления. Это устанавливается на всех новых компьютерах 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). Нехорошее решение идет вперед, но ...

+0

Разве это не так, поскольку программа Dell уже запущена - ваши запросы на DLL удовлетворяются уже существующим (если вы конкретно не назвали версию)? Что делать, если вы остановите программу Dell (и/или отключите ее и перезагрузите)? – TripeHound

+0

Я не думал, что эти побочные проблемы были вокруг (W7/8), но похоже, что что-то происходит. Я попросил пользователя загрузиться в безопасном режиме и сообщить о том, пропала ли проблема - как инструмент диагностики. – Matt

+0

В качестве продолжения - конечно, в простом случае с другим загруженным приложением и в настоящее время использующим предыдущую версию sqlite.interop.dll, это не влияет на ту версию, которую загружает наше реальное приложение (я это проверил) , Итак, что-то еще происходит. – Matt

ответ

10

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

Если вы указали force your app to load the correct library, как указано в dymanoid, ваше приложение выйдет из строя, когда отобразит диалоговое окно файла (потому что расширение оболочки сработает). Если вы этого не сделаете, ваше приложение выйдет из строя, когда оно попытается прочитать из своей базы данных.

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

Microsoft - aware of the problem, но отказался его исправить.

Желаю, чтобы ребята Dell внедрили расширение своей оболочки like this.

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() 

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

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 
    } 
} 
+0

Спасибо - я принимаю это как ответ на видимость, хотя я должен почетно упомянуть dymanoid, который также упомянул об этом в комментарии. Мы пришли к тому же выводу, что и вы, и теперь попросите пользователей удалить приложение Dell, но на самом деле у нас не было запроса поддержки по этой проблеме какое-то время, так что «с глаз долой, из сердца вон».Единственное решение, о котором я могу думать - если Microsoft не сделает что-то, чтобы исправить эту неприятность, - это перекомпилировать SQLite.NET для использования именованной interlo dll. – Matt

+0

Это точная проблема, из-за которой наше программное обеспечение врезалось в поле сегодня утром. К счастью, наше программное обеспечение установило фильтр необработанных исключений, который сохранил полную дамп (да). Открытие файла дампа в WinDbg, команда лм показывает, что вы два System_Data_SQLite модуля, другое имя System_Data_SQLite_73d20000, лм ут System_Data_SQLite_73d20000 показывает, что это абсолютный путь: C: \ Program Files (x86) \ Dell резервного копирования и Recovery \ Components \ Shell \ System.Data.SQLite.dll , что в конечном итоге приводит меня к Google и здесь. – zhaorufei

+0

Спасибо! Как я могу определить использование C#, если «Dell Backup and Recovery» установлен на компьютере? – Track

3

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

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

Source code is also available.

+0

Спасибо, что нашли время ответить - я ценю это. К сожалению, я прошел через эти шаги, и на самом деле также перешел через источник, который обрабатывает загрузку interop.dll, и все, что я вижу, говорит о том, что наша установка * должна * работать * (т. Е. У нас есть правильная interop dll в том же каталоге, что и исполняемый файл, но неправильная версия все еще загружена.). Я обновил этот вопрос несколькими подробностями. – Matt

+0

Вы пытались изучить журнал Fusion, чтобы узнать, как среда выполнения пытается разрешить ссылку? –

+0

Может ли Fusion помочь с явно загруженными родными DLL? Я (почти) уверен, что правильная сборка .NET загружается, так как мы не получили бы нерешенную внешнюю, если бы старая была загружена, - поэтому существует несоответствие между сборкой .NET и встроенной dll-оболочкой, которая загружается во время выполнения с помощью LoadLibrary(). – Matt

1

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

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

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

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

+0

Просто, чтобы уточнить, вы говорите о сборках «смешанного режима»? И они содержат все необходимое, в одной DLL, и ничего не нужно устанавливать в GAC? Звучит как простое решение, если оно верно - спасибо! – Matt

+0

Да, это так. Вам по-прежнему нужно загружать отдельные сборки x86 и x64 для установки на разные платформы, но вам не нужно ничего устанавливать в GAC – bvadala