DLL hell with SQLite

前端 未结 3 754
栀梦
栀梦 2021-02-18 14:15

Some of our users are getting an issue with the version of sqlite.interop.dll that is being loaded at runtime, and it\'s a real head scratcher.

Background: A WPF applica

相关标签:
3条回答
  • 2021-02-18 14:55

    We are dealing with this exact issue and the solution we found is to use the bundled package from the System.Data.SQlite website rather than the package from nuget: https://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki

    The bundled dll has both the managed and unmanaged assemblies merged so there is no need for dynamically loading the correct Sqlite.Interop.dll so you don't have the issue of conflicting versions in the appdomain.

    When using the bundled assembly you need to include your own logic in your application's installer to decide which dll to copy (x86 or x64).

    We haven't had any more issues with conflicting versions since using the bundled assembly.

    0 讨论(0)
  • 2021-02-18 15:11

    SQLite.Interop.dll is loaded in a tricky way.
    By using any reflector you can inspect UnsafeNativeMethods.Initialize() method in System.Data.SQLite.dll by yourself.
    Some notes to demonstrate, that it is possible to get something interesting by reflection(1.0.89 version):

    • If SQLite.Interop.dll is placed in base directory - it will be loaded
    • PreLoadSQLite_BaseDirectory and PreLoadSQLite_UseAssemblyDirectory environment variables can affect loading process
    • SQLite.Interop.dll can be searched in predifined subfolders(x86, x64, Win32, Itanium, WinCE)
    • Trace.WriteLine is called to inform selected path(not always)

    Source code is also available.

    0 讨论(0)
  • 2021-02-18 15:16

    Our app has the same problem. As you mentioned, the problem is that Dell Backup and Recovery installs a shell extension that uses old versions of several popular dlls. They play hell with any app that launches file dialogs and also uses those libraries, because shell extensions load their dlls into your AppDomain. The only solution we have so far is to tell the users to uninstall Dell Backup and Recovery.

    If you force your app to load the correct library as dymanoid mentioned, then your app will crash when it displays a file dialog (because the shell extension will crash). If you don't do that, then your app will crash when it tries to read from its database.

    Interestingly, Dell Backup and Recovery is a repeat offender; it also breaks QT5 in the same way. The recommended solution from the QT guys is to compile your QT library under a different name with the -qtnamespace [name] option. We might be able to rig something like that with system.data.sqlite, but then we'd have to compile our own version.

    Microsoft is aware of the problem, but has declined to fix it.

    I wish the Dell guys had implemented their shell extension like this.

    Portroit Pro, SONAR, and AutoDesk's solution to this problem is also to uninstall Dell Backup and Recovery.

    A typical stack trace of the problem looks this in our application:

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

    So in answer to Track's comment, if you want to detect this particular problem and give the users some special notice, you could do something like this:

    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 讨论(0)
提交回复
热议问题